In de vorige post had ik vier agents bedacht: OttoOps, DexterDev, PerryPO en PacoPA. Leuk op papier, maar ze deden nog niets.
Dus begin ik klein.
Aan het eind van deze post woont OttoOps op een eigen server. Ik kan hem vanaf mijn telefoon een bericht sturen via Telegram en hij stuurt antwoord terug.
Geen dashboard. Geen ingewikkeld agentsysteem. Gewoon:
ik → Telegram → OttoOps → Telegram → ik
En het mooie is: ik ga de server niet zelf met allerlei Linux-commando’s inrichten. Daarvoor gebruik ik eerst Claude Code op mijn eigen computer. Die noem ik in deze reeks LocalClaude.
LocalClaude is gereedschap, geen lid van mijn agentteam. Hij helpt me OttoOps op zijn plek te zetten. Daarna is zijn werk klaar.
Aan het eind van deze post staat de teller dus op:
Teamstatus: 1 agent — OttoOps
Stap 0 — Wat je nodig hebt
Voor we beginnen even praktisch.
Je hebt nodig:
- een computer waarop je Claude kunt draaien;
- een Claude Pro-account — op dit moment betaal ik daarvoor €15 per maand, exclusief btw;
- een virtuele server;
- een Telegram-account.
Voor de server gebruik ik Hetzner. Mijn kleine server kost €5,99 per maand exclusief btw.
Daarmee kom ik voor deze opzet op ongeveer €21 per maand exclusief btw.
De server hoeft niet zwaar te zijn. OttoOps gaat in deze reeks geen enorme modellen lokaal draaien; Claude Code gebruikt Claude op afstand. De server is vooral de plek waar OttoOps woont en waar hij zijn werk uitvoert.
Reken voor deze eerste post wel wat tijd. Niet omdat je veel zelf moet programmeren, maar omdat je een paar keer iets moet aanmaken, aanmelden en controleren.
Stap 1 — Eerst Claude op mijn eigen computer
Ik gebruik de desktopapp van Claude. Daar zit Claude Code in: Claude kan vanuit het gesprek bestanden maken en opdrachten op mijn computer uitvoeren.
In deze reeks noem ik deze Claude LocalClaude.
Ik maak eerst een lege map voor dit project. Niet mijn complete documentenmap, want alles wat ik aan de projectmap geef kan Claude in principe bekijken.

Kies voor Code en voeg die lege map toe aan Claude.

Mijn eerste opdracht is bewust simpel:
Ik ga in deze map werken aan het opzetten van een server met een AI-beheerder erop.
Laat me eerst zien dat je op deze computer dingen kunt uitvoeren: vertel me welk besturingssysteem ik draai, welke versie, en of het programma
sshbeschikbaar is.Leg je antwoord uit in gewone taal.
Daarmee gebeurt nog niets spannends. Maar ik weet nu wel dat Claude daadwerkelijk op mijn computer kan werken en dat ssh beschikbaar is.
Dat laatste hebben we zo nodig.
Stap 2 — Een sleutel voor de server
De server komt straks ergens op internet te staan. Daar wil ik natuurlijk niet met een simpel wachtwoord op inloggen.
Daarvoor gebruiken we een SSH-sleutel.
Je krijgt twee bestanden: een publieke sleutel en een geheime sleutel. De publieke sleutel mag naar de server. De geheime sleutel blijft op mijn computer.
Een beetje alsof ik een speciaal slot op de server monteer waarvan alleen ik de sleutel heb.
Ik laat LocalClaude het sleutelpaar maken:
Maak een SSH-sleutelpaar aan dat ik ga gebruiken voor één specifieke server. Gebruik het ed25519-type. Geef het paar een eigen naam (mijn-agents-server) waaraan ik kan zien waar hij voor is, dus niet de standaardnaam, ik wil hem later kunnen onderscheiden van andere sleutels. Gebruik geen wachtwoordzien (passphrase).
Vertel me daarna:
- het volledige pad van het geheime bestand en van het publieke bestand
- de inhoud van het publieke bestand
- of de rechten op het geheime bestand goed staan
Toon de inhoud van het geheime bestand niet, nu niet en later niet.
Claude maakt de twee bestanden aan en controleert meteen of de geheime sleutel alleen door mij gelezen kan worden.

Ik sla het pad naar mijn geheime sleutel op in mijn wachtwoordkluis. Ook de inhoud sla ik op als backup (zorg dus wel dat dit veilig opgeslagen staat).
Een afspraak met Claude
Er komt vanaf nu nog iets bij.
LocalClaude gaat straks daadwerkelijk dingen op mijn server veranderen. Ik wil daarom kunnen terugzien wat hij gedaan heeft, en ik wil vooraf weten wanneer hij iets gaat wijzigen.
Dus geef ik hem nog één opdracht:
Maak in deze map een bestand
CLAUDE.mdmet werkafspraken voor jezelf. Zet daarin, in gewone taal:
- Verbindingen met de server maak je via scripts in deze map, zodat ik kan teruglezen wat er is gebeurd. Geen losse commando’s die ik niet terugvind.
- Elk script begint met een nummer zodat duidelijk te zien is in welke volgorde de scripts gebruikt zijn. Begin met 00001.
- Voordat je iets uitvoert dat de server verandert, vertel je eerst wat je gaat doen.
Schrijf het zo op dat een andere agent die dit bestand voor het eerst leest, precies weet wat er van hem verwacht wordt.
Dit bestand blijft voortaan in de projectmap liggen.
Ik hoef die afspraak dus niet bij iedere opdracht opnieuw te herhalen.
Stap 3 — Een lege server
Nu heb ik iets nodig waar OttoOps kan wonen.
Ik gebruik hiervoor een server / VPS bij Hetzner. Een VPS is eigenlijk gewoon een kleine computer in een datacentrum die 24 uur per dag aanstaat.
Dit is één van de weinige dingen die ik bewust zelf doe. Niet omdat Claude geen server zou kunnen bestellen, maar omdat ik hier een betaald product afsluit. Ik wil zelf even zien wat ik koop.
Ik kies:
- Ubuntu als besturingssysteem;
- de nieuwste LTS-versie;
- de kleinste server die voor dit project voldoende is;
- backups aan.
Voor dit soort werk heb je echt geen enorme machine nodig.

Tijdens het aanmaken vraagt Hetzner om een SSH-sleutel.
Daar plak ik de publieke sleutel die LocalClaude zojuist heeft gemaakt.

Daardoor kan ik straks direct veilig op de server inloggen en hoef ik niet eerst met een wachtwoord aan de slag.
Als de server draait, noteer ik het IP-adres.
En ik maak meteen een snapshot.
Een snapshot is een soort bevroren kopie van de hele server. Als ik later iets grondig verpest, kan ik hiernaar terug.
Vanaf nu maak ik vóór iedere volgende blogpost zo’n snapshot.
Stap 4 — De eerste keer naar binnen
Nu mag LocalClaude voor het eerst naar de nieuwe server.
Hij gebruikt daarvoor ssh: daarmee kan hij vanaf mijn computer opdrachten uitvoeren op de server.
Eerst laat ik LocalClaude verbinding maken en controleren wat er staat:
Ik heb een nieuwe Ubuntu-server bij Hetzner met IP-adres [jouw IP]. Mijn geheime sleutel staat op [pad uit stap 2].
Maak in deze map een script waarmee ik verbinding maak met die server, zodat ik het later kan teruglezen en hergebruiken. Gebruik de sleutel via het pad; zet hem nergens in de tekst.
Log daarna in en vertel me: welke Ubuntu-versie draait erop, hoeveel schijfruimte en geheugen er is.
Bij de eerste verbinding vraagt SSH of ik deze server vertrouw. Dat bevestig ik één keer.
Daarna laat ik de voordeur meteen wat verder dichtzetten:
Zet nu het volgende goed op de server:
- Inloggen met een wachtwoord uitzetten; alleen nog met een sleutel.
- Een firewall aanzetten die alleen SSH doorlaat.
- De beschikbare updates installeren.
Stap 5 — Hier komt OttoOps
Tot nu toe werkt LocalClaude op de server als beheerder.
Maar mijn agent moet niet permanent als root gaan rondlopen. Daarom krijgt OttoOps zijn eigen gebruiker.
Dit is de opdracht die ik gebruik:
Maak op de server (IP: xxx.xxx.xxx.xxx) een gebruiker
ottoopsaan, login gebruik makend van de net aangemaakte sleutel.
- Geef hem een eigen thuismap.
- Geef hem volledige beheerrechten zonder dat er om een wachtwoord wordt gevraagd. Gebruik daarvoor een apart bestand in de sudoers-map, geen bewerking van het hoofdbestand, en controleer het bestand op fouten voordat je het wegschrijft.
- Zet mijn publieke sleutel ook bij hem neer, zodat ik rechtstreeks als deze gebruiker kan inloggen.
- Geef hem geen wachtwoord om mee in te loggen.
Laat me daarna zien dat het werkt: log in als
ottoopsen voer het commandosudo -luit
Claude vertelt vooraf wat hij gaat veranderen. Precies zoals we in CLAUDE.md hadden afgesproken.

Vervolgens controleert hij het resultaat.

ottoops bestaat, kan rechtstreeks met mijn sleutel inloggen en heeft beheerrechten.Er woont nu dus iemand met de naam OttoOps op mijn server.
Alleen is hij op dit moment nog geen AI-agent.
Dat wordt de volgende stap.
Stap 6 — Claude Code verhuist naar de server
Nu installeert LocalClaude Claude Code voor de gebruiker ottoops.
Daarbij laat ik hem bewust niet uit zijn geheugen werken:
Installeer Claude Code op de server, voor de gebruiker
ottoops. Zoek eerst op wat op dit moment de officiële installatiemethode is en welke vereisten erbij horen; ga niet af op wat je denkt te weten.Installeer het zo dat het van
ottoopsis en niet van root.
Daarna moet Claude Code nog worden gekoppeld aan mijn Claude-account.
Dat is net iets lastiger dan op mijn eigen computer. Op de server draait namelijk geen gewone webbrowser.
Daarom laat ik LocalClaude het inlogproces starten en open ik zelf de link op mijn computer:
Log op de server in bij Claude Code, als gebruiker
ottoops.
- Gebruik hiervoor het commando
claude auth login.- Het inlogproces is interactief en moet blijven draaien terwijl ik in mijn eigen browser de stap afrond. Start het daarom in een sessie die je later weer kunt benaderen (bijvoorbeeld
tmux), zodat je de code straks alsnog kunt invoeren. Start het proces niet opnieuw op als ik met de code kom.- Zodra er een URL verschijnt die gevolgd moet worden: stop en geef mij die volledige URL letterlijk terug, ongewijzigd en zonder afkorting. Vraag mij dan om de code die ik daarna te zien krijg.
- Ik geef je vervolgens de code. Voer die in in de nog lopende sessie en rond het inloggen af.
- Bevestig daarna dat het gelukt is met een controle die dat ook echt aantoont (bijvoorbeeld de authenticatiestatus opvragen of een korte testaanroep), niet op basis van “geen foutmelding”.
Ik open de URL, meld me aan en geef de code terug aan LocalClaude.
En daarmee gebeurt iets belangrijks.
Vanaf dit moment draait Claude Code als ottoops op de server.
LocalClaude heeft zijn werk gedaan.
OttoOps kan nu zelf aan de slag.
Stap 7 — OttoOps krijgt Telegram
Een agent op een server is aardig, maar ik wil niet iedere keer met SSH naar die server om iets te vragen.
Ik wil gewoon mijn telefoon pakken.
Daar komt Telegram bij.
Telegram laat je relatief eenvoudig zelf een bot maken. Daarvoor praat je in Telegram met BotFather.
Ik maak een nieuwe bot aan en krijg daarbij een token.
Dat token is feitelijk het wachtwoord van de bot. Dus ook hier geldt: niet in screenshots, niet in scripts en niet ergens achteloos in een projectmap zetten.
Ik bewaar het in mijn kluis en zet het daarnaast in een apart bestand in de map waar Claude Code bij kan .tg_ottoops.
Daarna geef ik OttoOps deze opdracht:
Ik heb een Telegram-bot gemaakt. Het token staat in .tg_ottoops; lees dit token zelf niet!
Kopieer .tg_ottoops en het script naar ottoops z’n thuismap op de server via scp (met de bestaande sleutel), lees de inhoud van het tokenbestand daarbij zelf niet!
Zet de rechten op het tokenbestand op de server strak (600, alleen leesbaar voor ottoops).
Maak een script (op de server) dat de wachtende berichten van de bot ophaalt en mij laat zien wie ze heeft gestuurd, inclusief het account-nummer van de afzender. Ik stuur eerst zelf een berichtje naar de bot, dan zien we mijn nummer.
Ik stuur de bot één keer hallo. Het script haalt dat bericht op en laat mijn Telegram-accountnummer zien.
Dat nummer gebruiken we in de laatste stap.
Dit stukje beveiliging is niet optioneel
Hier is het belangrijk om even stil te staan bij wat we eigenlijk aan het bouwen zijn.
OttoOps heeft volledige beheerrechten op deze server.
Dus als ik hem via Telegram zeg:
hoeveel vrije schijfruimte heb je?
dan mag hij dat bekijken.
Maar ik kan hem in principe ook opdrachten geven waarmee hij bestanden verandert, software installeert of andere beheeracties uitvoert.
Dat betekent dat niet iedereen die de Telegram-bot vindt met OttoOps mag kunnen praten.
Daarom halen we eerst mijn eigen Telegram-accountnummer op. In de volgende stap krijgt OttoOps de harde regel dat berichten van ieder ander nummer genegeerd moeten worden.
Zonder die controle zou iemand anders je bot kunnen aanschrijven en daarmee in feite opdrachten kunnen geven aan een agent die volledige toegang tot je server heeft.
Dat wil je dus absoluut niet overslaan.
Het Telegram-token beschermen en alleen berichten van je eigen account accepteren zijn hier geen nette extra’s. Ze zijn onderdeel van de beveiliging van de server.
Stap 8 — Een bericht erin, een antwoord eruit
Nu komt alles bij elkaar.
Het idee is eigenlijk opvallend eenvoudig.
Elke minuut kijkt een script of ik iets naar de Telegram-bot heb gestuurd.
Zo ja:
- het bericht wordt opgehaald;
- er wordt gecontroleerd of het bericht echt van mij komt;
- de tekst gaat naar Claude Code;
- OttoOps maakt een antwoord;
- het antwoord gaat terug naar Telegram.
Ik geef OttoOps daarvoor deze opdracht:
Maak een script dat het volgende doet, in deze volgorde:
- de wachtende Telegram-berichten ophalen;
- berichten van iemand anders dan mijn account-nummer negeren, zonder te antwoorden;
- de tekst van mijn bericht aan Claude Code geven en het antwoord opvangen. Start Claude Code daarbij zo dat hij niet om toestemming vraagt voor wat hij doet — er kijkt niemand mee die antwoord kan geven;
- dat antwoord terugsturen via Telegram;
- onthouden welke berichten al verwerkt zijn, zodat er bij de volgende ronde niet opnieuw op hetzelfde wordt geantwoord.
Zorg dat er nooit twee exemplaren van dit script tegelijk lopen: als de vorige nog bezig is, stopt de nieuwe meteen.
Laat het daarna elke minuut draaien, als de gebruiker
ottoops. Schrijf wat er gebeurt naar een logbestand, zodat ik kan terugkijken als er iets misgaat.
Bij mij gebeurde hier nog iets interessants.
Claude wilde het script wel maken, maar blokkeerde eerst het daadwerkelijk installeren van de taak die hem iedere minuut zou uitvoeren.
Niet vanwege Linux. Niet vanwege Telegram.
Omdat ik daarmee een stukje automatisering activeerde dat daarna zelfstandig bleef werken.

Ik gaf daar expliciet toestemming voor.
Daarna werd de taak geïnstalleerd en deden we meteen een echte test.

En dan het moment waarvoor we al deze stappen hebben gezet.
Ik pak mijn telefoon en stuur:
Hoeveel diskruimte heb je
Een minuut later antwoordt OttoOps:
Er is een schijf van 38 GB totaal, waarvan 2,0 GB gebruikt en 34 GB vrij.

Er woont nu echt een agent op mijn server
Op papier is wat we hebben gebouwd eigenlijk nog behoorlijk simpel.
Iedere minuut kijken of er een bericht is, controleren of het van mij komt, Claude Code aanroepen en het antwoord terugsturen.
Maar de beleving is totaal anders dan een gewone AI-chat.
Ik heb niet ergens Claude geopend en gevraagd hoeveel vrije schijfruimte een Linux-server normaal gesproken heeft.
Ik heb mijn eigen agent een bericht gestuurd:
Hoeveel diskruimte heb je?
OttoOps keek vervolgens op de machine waar hij zelf draait en gaf antwoord.
Dat is voor mij het punt waarop een naam uit een schema ineens een echte agent begint te worden.
Hij heeft een eigen plek. Hij heeft rechten. Hij kan dingen bekijken en uitvoeren. En ik kan hem gewoon vanaf mijn telefoon aanspreken.
Voorlopig is hij nog alleen.
Teamstatus:
- OttoOps — actief op zijn eigen server
DexterDev, PerryPO en PacoPA komen later.
En vanaf hier wordt het pas echt interessant.
Jouw reactie