Naar de inhoud

Blog ·

Webhosting verkopen met Plesk

Een Plesk-server tot hostingproduct maken: één sleutel voor twee API's, de opschortingsval die een account voor je pollen verbergt, en wat we nooit vragen.

Door Provibr

Plesk draait met alle plezier honderd abonnementen voor je. Wat hij niet doet is een bestelling aannemen, het geld innen, opmerken dat een factuur onbetaald bleef, of het account opschorten dat erbij hoort. Dat gat tussen “een paneel dat websites host” en “een hostingbedrijf” is waar het werk zit, en deze pagina gaat over het oversteken ervan zonder in de vier plekken te stappen die makkelijk in te stappen zijn.

Wat Plesk je al geeft

Een abonnement is de eenheid die je verkoopt: een hoofddomein, een serviceplan, schijf- en verkeerslimieten, en alles eronder. Een serviceplan is de eigen beschrijving van het paneel van dat pakket: quotum, maandelijks verkeer, hoeveel domeinen en mailboxen, welke diensten aan staan. Beide begrippen bestaan al, dus je vindt geen productmodel uit, je geeft een model dat er is een naam.

De API is goed op één manier die vooral voor een hostingproduct van belang is: één aanroep leest elk abonnement op de server, met zijn plan, status, quotum en verbruik. We maten dat op 0,33 seconden, ongeacht hoeveel het er zijn. Drie leesaanroepen geven je het volledige beeld van een server (abonnementen, klanten, plannen) en dat getal groeit niet mee met je klantenaantal. Datzelfde beeld over REST opbouwen zou één aanroep plus drie per abonnement kosten.

Eén sleutel opent twee API's, en je hebt ze allebei nodig

Plesk heeft een moderne REST v2-API en een oudere XML/RPC-API. Geen van beide is op zichzelf compleet, en dat is geen kwestie van voorkeur.

REST v2 heeft geen abonnementen en geen serviceplannen. We somden zijn 43 paden op uit zijn eigen OpenAPI-document; /subscriptions en /service-plans staan er niet tussen, en ze opvragen levert een 404 op die als HTML-pagina wordt gerenderd in plaats van als JSON. Omdat het serviceplan het hostingpakket is, moet de hele pakketkant over XML lopen.

De redding is het inloggegeven. De sleutel die POST /api/v2/auth/keys uitgeeft werkt ongewijzigd in allebei: als X-API-Key op REST en als KEY op het XML-endpoint. Gemeten, dezelfde sleutel, beide API's. Dus je vraagt de operator om één waarde, niet twee.

Wat het je kost zijn twee faalvocabulaires. REST beantwoordt een onbruikbare sleutel met HTTP 401 en een volledig lege body. XML beantwoordt dezelfde sleutel met HTTP 200 en een foutcode in het document. Wat ons bij de scherpe rand brengt.

Een authenticatiefout die eruitziet als een lege server

Omdat de XML-API HTTP 200 teruggeeft voor een slechte sleutel, leest een client die de statuscode controleert een authenticatiefout als een geslaagde ronde die niets vond. En een geslaagde ronde die niets vond heeft in elk hostingplatform een betekenis: elk account dat er gisteren was, is weg.

Het gevolg is geen kapot dashboard. Het is een systeem dat elk van je klanten als verwijderd markeert omdat een sleutel verliep. De regel die daaruit volgt is absoluut: op de XML-API draagt de statuscode helemaal geen informatie, zelfs niet over authenticatie. Parse het document, en behandel een onleesbaar antwoord als onbekend in plaats van als leeg.

Een lege server geeft ook geen fout: hij geeft één enkel leeg resultaat, wat het juiste antwoord is als er werkelijk geen zijn. Die twee uit elkaar houden is het hele werk.

De opschortingsval: schrijf en lees hetzelfde veld

Er zijn twee manieren om een abonnement in Plesk op te schorten en ze schrijven niet hetzelfde veld.

Wat je doetXML gen_info.statusREST-abonnementsstatus
niets (actief)0active
PUT /domains/{id}/status naar suspended0suspended
CLI subscription --webspace-off1suspended
XML <webspace><set> met status 1616suspended

Lees de tweede regel nog eens. Opschorten over REST laat het veld dat de bulk-poll leest op nul staan. Dus een hostingproduct dat over REST opschort en over XML pollt, toont het account als actief terwijl het in feite opgeschort is. Er gaat niets fout. Er wordt niets rood. Je paneel en je server zijn het simpelweg oneens, en de eerste die het merkt is een klant die een site niet kan bereiken waarvan jij denkt dat hij draait.

De regel: schort op en hervat via hetzelfde veld dat je leest. Provibr gebruikt XML <webspace><set><gen_setup><status>, en daarna bewegen beide beelden samen: het XML-veld meldt 16 en REST meldt suspended.

gen_info.status is een bitmask, en de waarden die we maten zijn 0 voor actief, 1 voor webspace-off en 16 voor uitgeschakeld door de beheerder. Alles wat niet nul is telt als opgeschort, wat de enige lezing is die een waarde overleeft die we nog niet gezien hebben.

Twee datasets die we het paneel nooit vragen

Plesk geeft geheimen af als je de verkeerde dataset opvraagt, en hij doet dat in leesbare tekst:

  • <webspace><get> met de hosting-dataset geeft het FTP-wachtwoord van het account in leesbare tekst terug, met een veld dat het expliciet als leesbaar markeert.
  • <customer><get> met de gen_info-dataset geeft de wachtwoordhash van de klant (bcrypt) terug, naast het hashtype.

Een redactielaag is het verkeerde antwoord hierop. Het juiste antwoord is niet vragen. De poll van Provibr vraagt precies vier datasets op (algemene info, limieten, statistieken en abonnementen) en we zijn ze veld voor veld doorgelopen om te bevestigen dat geen ervan een geheim draagt. De klantenlijst komt van REST, dat helemaal geen wachtwoordveld heeft.

Er is een ontwerpgevolg dat het vermelden waard is, want het verklaart iets wat er anders als een gat uitziet. De FTP- of systeemgebruiker van een abonnement zou een aantrekkelijke korte identifier zijn, maar die leeft alleen in de hosting-dataset, dus hem als identiteit gebruiken zou betekenen dat je bij elke pollronde het wachtwoord van elke klant ophaalt. Vandaar in plaats daarvan het domein.

De identiteit van een abonnement is een domeinnaam

In Plesk is een abonnement genoemd naar zijn hoofddomein. Dat is wat het paneel toont, waar de API van het paneel op filtert, en wat elke integratie moet opslaan.

Dit is een reëel verschil met cPanel en DirectAdmin, waar een account een korte gebruikersnaam en een domein apart heeft, en het heeft één praktisch gevolg: het domein kan achteraf niet meer gewijzigd worden. Wat je facturatiesysteem ook als identifier van een Plesk-abonnement opslaat, het is een domeinnaam, en een klant die zijn site wil hernoemen vraagt om een nieuw abonnement in plaats van om een bewerking.

Twee kleinere dingen onderweg gemeten. De eigen specificatie van Plesk zegt dat een klantwachtwoord 5 tot 14 tekens is; een wachtwoord van 22 tekens werd zonder klagen geaccepteerd, dus de gedocumenteerde limiet is niet de afgedwongen limiet. En Plesk kiest het IP-adres zelf uit zijn eigen pool, wat de reden is dat een hostingaccount in Provibr een leeg adresveld heeft tot het paneel er een meldt.

Een mislukte bestelling kan een half abonnement achterlaten

Gemeten: een domein aanmaken met een serviceplan dat niet bestaat antwoordt HTTP 404 met een duidelijke melding, en het domeinobject bestaat daarna alsnog, zonder hostingtype en met een lege documentroot. Plesk maakt eerst het object aan en past daarna het plan toe, en rolt niet terug wanneer de tweede stap faalt.

De klant betaalde, de bestelling mislukte, en de volgende poging mislukt nu anders, omdat het domein al in gebruik is, door een account dat ze nooit ontvingen. Zoek het plan dus op voordat je iets aanmaakt, uit de planlijst die je al ophaalde, en ruim op na elke mislukte aanmaak. Ter contrast: een veldvalidatiefout zoals een dubbele login komt terug als HTTP 400 en laat niets achter: die controle draait vóór het aanmaken, en alleen het opzoeken van het plan gebeurt te laat.

Geen vertraging, wat zeldzamer is dan het zou moeten zijn

Het verbruiksoverzicht van DirectAdmin loopt in beide richtingen ongeveer drie seconden achter op de werkelijkheid, wat een tweede gezaghebbende aanroep afdwingt. Plesk niet. We maten een aanmaak en een verwijdering tegen de bulk-read:

text
    0 ms  create
 4519 ms  create returns 201
 4957 ms  bulk read sees the subscription      <- immediately
 4957 ms  delete
12622 ms  delete returns 200
13001 ms  bulk read no longer sees it          <- immediately

Plesk is transactioneel: zodra de aanroep antwoordt, is de wijziging zichtbaar in de bulk-read. Eén gezaghebbende bron, geen tweede aanroep, geen wachten.

De tijden zelf zijn het vermelden waard. Een abonnement aanmaken duurt 4,1 tot 4,5 seconden en er een verwijderen 7,7 seconden, lang genoeg dat een klant die naar een bestelformulier kijkt te horen moet krijgen dat er iets gebeurt. Van plan wisselen duurt 1,5 seconde en opschorten 0,78.

Wat Provibr hiermee doet

Provibr zit tussen je facturatie en je Plesk-server. Je koppelt de server met één API-sleutel, en daarna is een abonnement een gewone regel: bestel het, schort het op, hervat het, verplaats het naar een ander serviceplan, verwijder het.

  • Eén sleutel, want dezelfde sleutel opent beide API's.
  • Opschorten gaat door het veld dat de poll leest, dus paneel en server kunnen niet uit elkaar lopen.
  • De poll vraagt nooit een dataset op die een wachtwoord bevat, dus geen enkel klantgeheim bereikt het platform.
  • Het plan wordt opgezocht vóór de aanmaak, en een mislukte aanmaak wordt opgeruimd in plaats van achtergelaten.
  • Niets wordt op zijn eigen woord vertrouwd. Elke mutatie eindigt met het abonnement terug te lezen.
  • De agent belt uitgaand vanuit je netwerk, dus poort 8443 kijkt niet uit op het internet en er wordt niets op de Plesk-server geïnstalleerd.
  • Abonnementen die je niet via Provibr besteld hebt worden met rust gelaten tot je ze importeert, wat een server met tweehonderd bestaande klanten iets maakt om over te nemen in plaats van een herbouw.

Wat het niet doet

Het beheert abonnementen op een Plesk-server die jij bedient, niet de server zelf: diensten, DNS-zones, mailrouting en de instellingen van het paneel zelf blijven waar ze zijn. Er is geen console, want een hostingaccount is geen machine. Mailboxen, databases en DNS binnen een abonnement zijn van Plesk en van je klant.

Eén eerlijk gat: alles hier is gemeten met een beheerderssleutel. Of een sleutel met reseller- of klantbereik de XML-API überhaupt kan gebruiken is ongetest, dus de integratie probeert het bij het koppelen en weigert inloggegevens die maar een deel van een paneel kunnen zien in plaats van stilletjes de helft ervan te beheren.

Lees verder

Gemeten tegen Plesk Obsidian 18.0.80 in augustus 2026, met alle antwoorden als fixtures vastgelegd. Gedrag met een sleutel met resellerbereik, met meer dan één abonnement per klant, en onder echte verkeersbelasting is niet gemeten, en is als zodanig hierboven vermeld.

Begin met één host en één agent

Maak een account aan, installeer de agent met één commando en koppel je eerste Proxmox-host. De proefperiode loopt 14 dagen en vraagt geen betaalgegevens.