Blog ·
Automatizar la facturación en CloudPanel
Un pedido pagado, una factura vencida, una cancelación. CloudPanel tiene un comando para dos de esos tres momentos. El tercero es una edición de vhost.
Por Provibr
Un producto de alojamiento automatizado tiene exactamente tres momentos en los que el dinero y las máquinas se tocan:
- El pedido se paga. El sitio debe existir, correctamente configurado, en cuestión de segundos.
- La factura está vencida. El sitio debe apagarse, y volver en cuanto se pague.
- La suscripción termina. El sitio debe eliminarse, de verdad, datos incluidos.
CloudPanel tiene un comando limpio para el primer momento y un comando limpio para el tercero. Para el segundo no tiene nada en absoluto. Eso no es una pequeña nota al pie sobre una integración por lo demás ordinaria; es el hecho determinante de automatizar la facturación en este panel, y merece el medio de esta página en lugar de una línea al final.
Los tres momentos, y qué ofrece CloudPanel
| Momento | CloudPanel | ¿Existe? |
|---|---|---|
| Pedido pagado | clpctl site:add:php (más clpctl db:add para una base de datos) | Sí |
| Vencido | Sin comando; el vhost es la palanca | No en el panel |
| Pagado al final | Sin comando; la misma palanca, invertida | No en el panel |
| Subida / bajada de plan | Sin comando; no hay noción de paquete | No |
| Cancelación | clpctl site:delete --domainName=… --force | Sí |
Todo pasa por clpctl, la herramienta de línea de comandos del panel. No hay API REST: CloudPanel es un panel renderizado en el servidor más una CLI, y la automatización pasa por esa CLI o no pasa.
Los dos comandos que sí existen son buenos. site:add:php toma el dominio, la versión de PHP, una plantilla de vhost y el usuario Linux del sitio con su contraseña, y devuelve el control una vez escritos el vhost, el pool y el directorio personal. site:delete --force es una eliminación de verdad, no una blanda. Entre ambos está el hueco.
El medio que falta, y cómo se rellena
La suspensión es la acción que un sistema de facturación ejecuta más que ninguna otra, porque es la que corre sin supervisión, según un calendario, contra cuentas que nadie mira. Es también la única palanca reversible que hay entre «seguir alojándolos gratis» y «eliminar su negocio».
CloudPanel no tiene palabra para ello. No hay site:suspend, no hay site:disable, ningún indicador de mantenimiento en el panel, y ningún estado por sitio que se pueda cambiar. Así que si vende alojamiento CloudPanel, la suspensión es algo que construye. Las opciones realistas, con su coste honesto:
Detener el pool PHP-FPM del sitio. Rápido, reversible, y detiene de verdad que el sitio sirva. También produce un 502 en lugar de una explicación, así que su cliente ve un sitio web roto en lugar de una cuenta suspendida. Y es una operación de systemd en el host, no una de clpctl, así que es cosa suya mantenerla funcionando a lo largo de las actualizaciones del panel.
Editar el vhost. La configuración NGINX del sitio es un archivo en el host, y una sola línea decide si el sitio responde. Reversible, instantáneo, y no le cuesta al cliente más que el acceso. El truco es que se escribe en un archivo que CloudPanel posee, así que importa muchísimo cómo se escribe en él.
Eliminar, con una copia de seguridad primero. Sin ambigüedad, y permanente de una manera que acabará costándole un cliente que pagó el día treinta y uno. Restaurar no es un interruptor, con todo lo que eso implica para el DNS, los certificados y el correo que hay que enviar después.
No existe una cuarta opción que sea limpia. Lo que importa es elegir una deliberadamente y asegurarse de que la persona que responde al teléfono sabe cuál es. El modo de fallo aquí no es técnico: es un agente de soporte que le promete a un cliente que su sitio volverá enseguida, en un sistema donde volver significa restaurar una copia de seguridad.
Qué aspecto tiene una edición de vhost cuidadosa
La segunda opción es la que vale la pena hacer correctamente, y «correctamente» cabe en una lista corta. Así es como lo hace Provibr, y el razonamiento se traslada tanto si usa Provibr como si lo escribe por su cuenta.
Marque lo que inserta. La suspensión es un return 403; envuelto entre un comentario de inicio y uno de fin. Retirarla significa eliminar exactamente las líneas entre esos marcadores. Así, la reactivación deja el archivo byte a byte tal como estaba, y un return 403; que el cliente puso ahí por sus propias razones sobrevive intacto. Un buscar-y-reemplazar sobre return 403 no tendría esa propiedad.
Cada bloque server público, no el primero. Un vhost suele tener un bloque para el puerto 80 y uno para el 443. Si inyecta en uno solo, obtiene un sitio suspendido por HTTP y otro perfectamente sano por HTTPS, lo cual es peor que no suspender en absoluto, porque parece que funcionó.
Pruebe la configuración antes de recargarla. nginx -t se ejecuta primero. Una suspensión que tira abajo todos los demás sitios de la máquina no es una suspensión, y esto es un servidor web compartido por diseño.
Haga que el estado sea legible desde el host. Como el marcador es un comentario en un archivo, los sitios suspendidos están a un grep de distancia y el agente lo vuelve a leer en lugar de fiarse de su propia base de datos. Si alguien edita el archivo a mano, el siguiente sondeo lo nota.
Lo que nada de esto cambia: CloudPanel mismo sigue sin tener un concepto de sitio suspendido. El panel lo mostrará como un sitio corriente, porque desde el punto de vista del panel lo es. Cualquiera con acceso a CloudPanel, incluido el cliente que acaba de suspender, puede abrir ese archivo y quitar la línea. El estado es legible y se aplica en el servidor web, pero no lo posee el panel, y ningún montaje sobre este panel puede lograr que sea así.
Tampoco hay un camino de subida de plan, porque no hay paquetes
CloudPanel no tiene planes, ni cuotas, ni límites por sitio. Eso quita un momento entero de la lista de arriba: no hay una llamada «cambiar de paquete», porque no hay paquete.
También significa que la diferencia entre sus planes tiene que ser real en algún otro sitio. Si su plan de 5 € y su plan de 15 € aterrizan en el mismo CloudPanel con todo igual, entonces lo que su cliente compró fue un precio, y el primero que se dé cuenta se lo dirá a los demás. La aplicación de los límites vive por encima del panel: hosts distintos por tramo, cuotas a nivel del sistema de archivos, o límites que su propia plataforma aplica y cuenta.
La reconciliación necesita una lista, y no la hay
clpctl sabe listar los usuarios del panel. No sabe listar los sitios: esos viven en la propia base de datos SQLite del panel, en el host.
Para la facturación eso es un agujero real, porque se supone que un sistema de facturación puede plantear dos preguntas en cualquier momento: ¿existe todavía todo lo que cobro? y ¿hay aquí algo por lo que no cobro? A ambas se responde comparando sus registros con una lista de lo que hay realmente en la máquina. Sin una lista, se entera de un sitio eliminado a mano cuando el cliente escribe, y de uno creado a mano nunca.
Lo que sea que construya sobre CloudPanel tendrá que sacar esa lista de otro sitio que no sea clpctl, y necesitará acceso al host para hacerlo. En la práctica solo hay un lugar: la propia base de datos del panel, /home/clp/htdocs/app/data/db.sq3, donde un simple select sobre la tabla site da de una sola vez el dominio, el usuario Linux, el tipo, la plantilla de vhost y la versión de PHP. Provibr la lee ahí.
Eso funciona, y vale la pena ser claro sobre lo que se acepta al hacerlo. Ese esquema es asunto interno de CloudPanel, no una interfaz publicada, así que puede cambiar en una versión sin que nadie haya roto una promesa. Leerlo es la decisión correcta (un sistema de facturación sin reconciliación es peor), pero está en la corta lista de cosas que revisar de nuevo tras una actualización del panel, junto a los formatos de salida de clpctl.
La credencial no es un token de API
Vale la pena ser franco al respecto, porque es la mayor diferencia práctica entre automatizar CloudPanel y automatizar un panel con una API REST.
clpctl corre como root. Escribe configuración NGINX, crea usuarios Linux y gestiona servicios, así que root no es un descuido: es el trabajo. Cualquier cosa que lo gobierne posee, por tanto, acceso administrativo a un servidor web de producción que lleva los sitios de otras personas, no un token de alcance limitado a una sola superficie de API.
Dos consecuencias para quien conecte facturación a esto. El alcance de los daños es distinto: un token de API de panel filtrado permite a alguien crear y eliminar cuentas, mientras que una credencial de shell filtrada en el servidor web es otra conversación, con otro conjunto de obligaciones. Y el mínimo privilegio es su propio trabajo: no hay una casilla de permisos en la que apoyarse, así que la acotación se diseña en lugar de configurarse.
Dónde vive realmente la factura
Vale la pena ser explícito, porque es el malentendido más común: Provibr no factura a sus clientes. No les envía una factura, no los persigue, y no sabe qué les cobra. Esa relación es suya.
Lo que Provibr factura es su propia capacidad reservada: cuántas cuentas de alojamiento puede hacer correr a la vez, al mes, a un precio unitario por tramos. Lo que cobra a sus propios clientes, y cómo, se queda enteramente dentro de su propio sistema de facturación.
Hay dos maneras de conectar las dos mitades:
Un módulo de WHMCS. Si ya hace correr WHMCS, instale el módulo de aprovisionamiento de Provibr y haga que un producto de WHMCS apunte a un plan web de Provibr. Su cliente conserva una cuenta, una factura y un inicio de sesión. El módulo es un simple zip que instala por su cuenta, y corre dentro de su WHMCS. No hay nada que habilitar por nuestro lado.
La API REST. Si hace correr FOSSBilling, Blesta, algo propio, o una hoja de cálculo y una tarea programada, gobiérnelo directamente. Una clave, una URL base, y exactamente los permisos que ya tiene el miembro detrás de la clave.
La única regla para gobernarlo desde su propio código
Todo lo que toca una máquina es asíncrono, y tiene que serlo. Su infraestructura solo es alcanzable a través del agente que está dentro de su propia red, y ese agente marca hacia fuera. Así que un endpoint que cambia una cuenta no puede responder con el resultado. Responde que el pedido fue aceptado y le entrega un comando a seguir, que se lee hasta que su estado sea definitivo: terminado, fallido, expirado o cancelado.
La lectura nunca funciona así. Un inventario, una dirección o una factura responde de inmediato, porque esa respuesta viene de una base de datos y no de su host.
La consecuencia práctica para un gancho de facturación: no marque el pedido como completo sobre la respuesta de aceptación. La primera respuesta que obtiene es «lo hemos enviado», no «funcionó».
La suspensión es también su propio control de costes
Una conexión fácil de pasar por alto, y la razón por la que el medio que falta de arriba cuesta dinero además de buena voluntad. En Provibr, un servidor suspendido deja de contar para la capacidad que paga. Para una cuenta de alojamiento no existe un «detenido»: hay activo, y hay suspendido.
Así que el paso de reclamación de pago que ya quería por razones comerciales también libera la plaza que está pagando, siempre que la suspensión sea una acción real en lugar de una nota en su propia base de datos. Ese es el argumento práctico para construirla en lugar de dejar el medio vacío: una cuenta impagada que todavía no ha decidido eliminar es capacidad que sigue pagando.
Todo lo anterior sobre el panel es una propiedad de CloudPanel y no la descripción de una integración, lo cual es deliberado: los huecos son reales y no nos toca a nosotros hacerlos desaparecer con el deseo. Lo que una integración sí puede hacer es elegir con cuidado cuál de las tres opciones toma, y decir en voz alta qué es lo que esa elección todavía no arregla.
Si también vende VPS, servidores de juego o cuentas cPanel, los mismos tres momentos se aplican a todos ellos, y pueden vivir en un solo inventario. Provibr hace correr hoy sus paneles de control, sus hipervisores y sus paneles de juego unos junto a otros, con un único conjunto de permisos y un único registro de actividad sobre el conjunto.