Qué hay de nuevo
Cada función, corrección y mejora publicada en sh0. 29 fases, 2 auditorías de seguridad, más de 90 sesiones de ingeniería -- construido desde cero en Rust.
v1.10.0: el puerto que eliges llega a tu aplicación
Dos versiones desde la v1.8.0. La que importa: el puerto escrito en el formulario de despliegue por fin llega a la propia aplicación. Un campo rellenado de antemano con 80 neutralizaba en silencio dos correcciones ya entregadas, y ninguna prueba unitaria podía verlo: cada capa era correcta por separado. Además, una red de seguridad bajo el segundo factor, una página de acceso un 99,5 % más ligera al volver, y un dominio propio para el panel.
Endpoints API
Herramientas MCP
Pruebas aprobadas
Plantillas de despliegue
Cronología de desarrollo
Desde el primer commit hasta listo para producción -- el historial de construcción completo
v1.10.0: el puerto que eliges llega a tu aplicación
- El puerto que escribes llega ahora a tu aplicación. Un formulario de despliegue rellenado con 80 hacía que todas las aplicaciones declarasen un puerto explícito, lo que neutralizaba de golpe dos correcciones ya entregadas: el valor llegaba a `EXPOSE`, al puerto publicado y a la sonda de salud, pero nunca al proceso. El campo ahora sale vacío en las cuatro vías —envío de archivo, git, Dockerfile, imagen Docker—, doce plantillas más escriben `ENV PORT`, las plantillas Java escriben `ENV SERVER_PORT` para Spring Boot, y cuando no dices nada decide el `EXPOSE` de la imagen.
- Una sonda de salud que falla nombra el puerto realmente abierto: «Nothing answers on port 3000; the container listens on 9091». Un Dockerfile que no declara ningún `EXPOSE` dice a qué puerto ha recurrido en lugar de hacerlo en silencio, y un puerto que contradice el `EXPOSE` de la imagen se señala antes del despliegue, no después.
- El segundo factor gana una red de seguridad y una memoria. Los códigos de respaldo sobreviven a la recarga del perfil que los borraba, se regeneran desde el panel con un código nuevo del autenticador, y cada acceso protegido —por contraseña o por Google— escribe una línea fechada en el registro de auditoría, rechazos incluidos.
- El peso. Un visitante descarga un idioma en vez de cinco, y los recursos estáticos se almacenan en caché, se revalidan por ETag y se precomprimen en brotli y gzip. La página de acceso pasó de 1106 KB a 168 KB en la primera visita, y a 763 bytes en la siguiente.
- El enlace con la nube pasa a ser propio de cada instancia. Cada instalación lleva ahora su credencial y un canal cifrado hacia el proxy, en lugar de una clave compartida por todos, y el panel puede mudarse a un dominio tuyo: anunciado en el panel, con la dirección antigua nombrada en el momento en que deja de responder.
- Y el resto: once bucles de fallo en plantillas leídos y clasificados —ocho corregidos, dos retirados—, un nombre de host de servicio que ya no sirve el contenido del contenedor principal, un cambio de contraseña que revoca de verdad las demás sesiones, y los orígenes de Google Identity autorizados por la política de seguridad de contenido. Cada corrección lleva aquí una observación fechada en una máquina real; el contador de «corregido en código, nunca visto funcionar» sigue en cero.
v1.9.0: un dominio para el panel, y fallos que se distinguen
- El panel recibe una vía de adopción para su propio dominio. Ponerlo o quitarlo nombra la dirección que va a dejar de responder, una retirada fallida se muestra en rojo en lugar de un falso éxito, y el cambio solo se ofrece cuando el certificado ya está activo.
- Tres fallos distintos del proxy devolvían el mismo 404. Ahora devuelven tres códigos diferentes, y un dominio conocido al que le falta el destino ya no se declara desconocido.
- Las tres etiquetas de estado del panel hablan el idioma del panel en lugar de responder siempre en inglés.
- El documento OpenAPI anuncia la versión del binario que realmente lo sirve, en vez de un número fijado en el código.
v1.8.0: proyectos multiservicio, copia de seguridad de la instancia, actualización autónoma
- Los servicios de un proyecto se comunican por su nombre. Un alias interno estable (`<app>.internal`) sigue al contenedor cuando cambia su dirección: al redesplegar, la IP pasa de 172.20.0.4 a 172.20.0.5, el nombre sigue respondiendo y no hay que editar ninguna URL. Variables compartidas a nivel de proyecto, orden de arranque e importación de Compose de extremo a extremo.
- sh0 se respalda a sí mismo. `sh0 instance backup` toma una instantánea coherente de su propia base de datos mediante `VACUUM INTO` — nunca una copia de archivo, la base funciona en WAL —, deja la clave maestra fuera del artefacto pero registra su huella, y `sh0 instance restore` la restaura en una máquina nueva. Además, importación de proyectos entre instancias y rotación de la clave de cifrado de los secretos.
- El diagnóstico llega durante la espera, no después de ella. Los registros del contenedor se muestran mientras corre la sonda de salud, cada paso de construcción informa de su coste, una línea de contexto abre el registro de construcción, el estado del disco se lee desde la API, la recolección de capas pendientes queda registrada y una alerta precede a la saturación en lugar de constatarla.
- La vía de archivo, para quien despliega su propio código sin repositorio git. El tipo de aplicación se acepta al subir, el comando de arranque es configurable, un fallo de construcción muestra su línea de contexto y su causa, y un worker sin puerto ya no retiene la subida durante 300 segundos dejando un contenedor detrás. Node, Python, Go y Rust desplegados por ambas vías, archivo y Dockerfile.
- Una instalación se repara y se actualiza sin SSH. `sh0 update` elige su canal — estable o preliminar —, verifica la suma de comprobación del binario descargado y retrocede en ambos sentidos; una actualización ya no interrumpe las aplicaciones desplegadas. `sh0 doctor` comprueba Docker, los puertos, el disco, los certificados y el reloj, y termina con error cuando algo falta. Desinstalación limpia y unidad systemd endurecida.
- El correo y el almacenamiento de archivos pasan a ser utilizables: Stalwart v0.16 controlado mediante JMAP, las rotaciones automáticas de DKIM reflejadas en el DNS, una credencial rechazada que lo dice en lugar de callar. Y cuarenta y ocho correcciones, cada una con una observación fechada en una máquina real: no un test unitario, una máquina.
v1.7.1: licencias con fecha, renovación automática
- Una licencia ahora lleva una fecha de caducidad alineada con la suscripción que la pagó. Las suscripciones mensuales emitían licencias perpetuas: un mes pagado daba acceso de por vida.
- Una pasada diaria recupera la clave renovada, verifica su firma y sustituye la almacenada: nada que hacer cuando se renueva una suscripción. Una suscripción cancelada revoca la clave y el plan decae en la siguiente pasada.
- Desafío DNS-01 por dominio: un servidor detrás de un CDN que termina el TLS (nube naranja de Cloudflare) obtiene ahora un certificado sin desactivar su protección, en lugar de agotar su presupuesto de Let’s Encrypt en bucle.
- Enrutamiento y ciclo de vida: un reinicio que cambia el puerto publicado actualiza la ruta de Caddy; una aplicación que no escucha en el puerto configurado ya no se declara sana mientras devuelve 502; un redespliegue ya no deja el contenedor antiguo vivo junto al nuevo.
- Los límites de recursos siguen al hardware y no a la licencia en instalaciones autoalojadas, y los actualizadores de estado SSL ya pueden degradar un certificado, no solo promoverlo.
- La v1.7.1 es necesaria para cualquier licencia comprada después del 9 de septiembre de 2026. Las versiones anteriores no saben recuperar una renovación y se detienen al final del primer periodo.
v1.7.0: una licencia es un documento firmado
- Una clave de licencia es ahora un documento firmado con Ed25519 que lleva su propio plan, y no una cadena cuyo prefijo se daba por bueno. Cualquier cadena no reconocida activaba el plan Pro.
- La verificación es sin conexión: la clave pública viaja dentro del binario, así que un servidor aislado de la red valida su licencia sin llamar a nada.
v1.6.29: correcciones del dogfooding -- paridad .dockerignore, bucles de fallo nombrados, aplicaciones worker sin puerto
- El contexto de build aplicaba un patrón de .dockerignore sin barra a cualquier profundidad (semántica gitignore); Docker ancla cada patrón en la raíz y solo **/ desciende. Un proyecto que ignoraba *.md e importaba src/lib/resources/x.md compilaba en Easypanel y fallaba en sh0. sh0 aplica ahora las reglas de Docker; su propia lista generada escribe **/ explícitamente.
- El bucle de salud solo leía State.Running. Un contenedor que sale al arrancar bajo unless-stopped se reinicia en menos de un segundo: parecía en marcha, la sonda TCP fallaba 300 s y el registro concluía en tiempo de espera. El bucle lee ahora RestartCount y Restarting, falla en segundos con "crashed N times (exit code X)", detiene el bucle y nombra un OOM-kill. v1.6.30, el mismo día: el código de salida y el indicador OOM se leen en una instantánea detenida, ya que Docker los reinicia en cuanto relanza el contenedor -- un OOM-kill se anunciaba como "exit code 0".
- Los builds de imagen usaban rm=true, que solo elimina los contenedores intermedios si el build tiene éxito; cada build fallido dejaba un contenedor Exited (1) con nombre aleatorio que ninguna limpieza veía. forcerm=true lo elimina en ambos casos.
- Las aplicaciones tienen un tipo: web (sin cambios) o worker. Un worker no resuelve ni publica puerto, no recibe ruta Caddy ni dominio de vista previa, y está sano cuando permanece en marcha 15 s sin reinicio. Celery, BullMQ y los procesos tipo cron se despliegan sin que los mate una sonda a la que nada podía responder. Los formularios del panel exponen la elección.
Corrección v1.6.28: la API se congelaba tras dos redespliegues, y Sinatra respondía 403
- El proxy de previsualización de las direcciones *.sh0.app mantenía vivo un guard de lectura de DashMap durante toda la petición reenviada, horas en un WebSocket. La purga de caché añadida al redesplegar bloqueaba entonces un hilo del runtime, un escritor en espera bloqueaba a los nuevos lectores, y dos redespliegues con tráfico congelaron la API con cientos de conexiones en cola. La entrada de la caché ahora se copia antes de cualquier await. No instale v1.6.27 en producción.
- La plantilla Ruby nunca definía RACK_ENV: Puma arrancaba en desarrollo y la autorización de host de Sinatra 4 devolvía 403 a todo host público mientras la sonda en localhost pasaba. La etapa de producción ahora define RACK_ENV y RAILS_ENV en production.
Diecinueve correcciones antes de producción: contexto de build, inicio de sesión en claro, plantillas rotas y un instalador que trae Docker
- Contexto de build: una sola ruta de más de 100 bytes hacía fallar el archivo tar (la cabecera GNU no tiene campo prefix); las rutas largas viajan ahora como enlaces largos GNU. sh0 también reemplazaba el .dockerignore del proyecto por su propia lista, que excluía todos los *.md: el archivo del proyecto ahora se lee y se completa, no se impone nada cuando usted trae su Dockerfile, y se registra el número de archivos excluidos.
- Autenticación: las cookies de sesión y de refresco llevan Secure cuando la petición llegó por HTTPS, el puerto 80 responde un 308 hacia https:// para cada host gestionado (los desafíos ACME siguen pasando), el instalador advierte que el primer inicio de sesión por IP va en claro y muestra cómo poner un dominio TLS en el panel, y las credenciales ficticias [email protected] desaparecen del instalador, del panel y del banner del servidor.
- Stacks: Go compila cualquier versión de go.mod (GOTOOLCHAIN=auto sobre una imagen actual) y encuentra la raíz de su módulo cuando el binario vive en cmd/<nombre>; la configuración de Bundler en Ruby llega a la etapa de producción y Puma se enlaza una sola vez; .NET deduce su ensamblado de entrada al compilar, incluye curl para su sonda y corre en .NET 10 con roll-forward. Un redespliegue o un escalado ya no sirve 502 en *.sh0.app mientras expira la caché.
- Plataforma: una cadena de licencia desconocida se rechaza en lugar de activar Pro, el mensaje de cuota nombra el proyecto que ocupa la plaza, `sh0 users list` lee la base local en la máquina servidor, el proxy en la nube enruta /api/* a su aplicación en lugar de responder por ella, la tarjeta Active Servers del sitio lee latidos reales, y get.sh0.dev instala Docker (o falla pronto con el comando exacto) antes de escribir la unidad systemd.
Dos correcciones antes del dogfooding: los contenedores detenidos sobreviven a la limpieza, los certificados bajo demanda ya no exigen correo
- La limpieza horaria de Docker eliminaba todos los contenedores detenidos gestionados por sh0, incluido el de una aplicación que acababa de fallar: código de salida, registros y el botón Iniciar desaparecían con él. Un contenedor detenido se conserva ahora mientras una fila de la base de datos lo referencie; solo se eliminan los verdaderos huérfanos, y el paso se omite en lugar de ejecutarse a ciegas si la base no puede leerse.
- La emisión de certificados bajo demanda solo se armaba con un correo ACME configurado, aunque el registro decía que estaba armada en todos los casos -- en una instalación por defecto, Caddy seguía emitiendo al cargar la ruta. La política comodín bajo demanda se emite ahora con o sin correo; el correo simplemente se omite del emisor cuando no existe.
Cuatro lotes salen juntos: bloqueo de instancia, certificados bajo demanda y un estado SSL honesto
- `sh0 serve --port 9001` junto a una instancia en marcha instalaba paquetes, migraba la base de datos y detenía el Caddy en ejecución antes de descubrir que no podía arrancar. Un `flock` consultivo sobre `sh0.pid` rechaza ahora la segunda instancia de inmediato, indica el PID que ocupa el directorio y no toca nada. Un fallo deja el archivo sin consecuencias: el bloqueo muere con el proceso, y el siguiente arranque continúa.
- Los certificados se emiten bajo demanda, en el primer saludo TLS, en lugar de al cargar la ruta -- un dominio cuyo DNS aún no ha llegado ya no consume un intento de Let's Encrypt. Un dominio permanece `pending` hasta que alguien se conecta, y la insignia dice ahora por qué (`ssl_pending_reason`). `ssl_expiry` era siempre `null`; ahora se lee del certificado en disco. Un dominio `active` cuyo certificado desaparece vuelve a `pending` tras dos comprobaciones consecutivas.
- Un contenedor en bucle de fallos se declaraba `running` porque solo se leía el estado de Docker; el contador de reinicios y el código de salida forman ahora parte del veredicto. Las rutas de streaming de Docker tenían búferes en memoria sin límite -- sh0 fue eliminado por OOM a 7,3 GB en aislamiento -- y ahora están acotadas. El servicio de una pila Compose que recibía la ruta pública se elegía por el orden de iteración de una tabla hash y podía cambiar entre despliegues; ahora es determinista.
- Las suscripciones de la página de estado estaban muertas por construcción: el correo de confirmación nunca se enviaba mientras la API afirmaba lo contrario. El formulario solo aparece ahora si SMTP está configurado, las suscripciones sin confirmar se limitan a 200 por dominio, y las filas sin confirmar se purgan a las 48 horas en lugar de 7 días.
- «Ejecutar ahora» en una programación de copias lanzaba una copia puntual cuyos archivos escapaban a toda retención; ahora ejecuta la propia programación. `restore-external` rechazaba un servidor de base de datos nunca aprovisionado pero aceptaba uno detenido; un servidor detenido también se rechaza de forma síncrona.
- El importador de Compose exigía `image:` e ignoraba `build:` en silencio; ahora rechaza un servicio `build:` con un mensaje que dice qué hacer. `--acme-email` se persiste como `--panel-domain`, así que las renovaciones dejan de depender de un valor de reserva no verificado. Y la API ya no anuncia `panel_domain_ssl: "provisioning"` cuando no hay ningún aprovisionamiento en curso.
Laravel se despliega, Compose habla la forma larga y el puerto deja de perderse
- Toda aplicación Laravel se construía como Node. El detector se detenía en el primer `package.json`, y un Laravel moderno siempre trae uno porque así compila Vite los recursos, de modo que el contenedor moría en `npm start`, un script que ningún `package.json` de Laravel contiene. Ahora PHP gana ese empate cuando el proyecto lo demuestra: un framework en `composer.json`, un `artisan` o un `public/index.php`. Un proyecto Node que solo incluye una biblioteca PHP sigue siendo Node.
- Detectar Laravel no era hacerlo funcionar. El `package.json` pasa a ser una etapa de recursos dentro de la imagen PHP, Composer se instala en dos pasos porque `artisan` aún no existe en el primero, se acuña una `APP_KEY` en el primer despliegue y se guarda cifrada en lugar de quedar dentro de la imagen, y los controladores de sesión, caché y cola usan por defecto los que no necesitan base de datos. Esto último apareció al desplegar en la máquina de demostración y recibir un 500, no leyendo código.
- Los archivos Compose escritos en forma larga para `ports` y `volumes` fallaban al leerse — `invalid type: map, expected a string`. Ambas claves aceptan ahora cualquiera de las dos formas, enteros sueltos incluidos, y `read_only: true` produce un montaje realmente de solo lectura. Una ruta del host en forma larga se sigue rechazando, pero el rechazo nombra la política en vez de devolver un error de tipo.
- En la vía de imagen Docker, el puerto resuelto servía para publicar el contenedor y luego se descartaba: una aplicación desplegada sin puerto devolvía `port: null`, y cualquier dominio asociado enrutaba al 3000 mientras el contenedor escuchaba en otro sitio. Ahora el puerto se guarda en todas las vías, y la prueba añadida no comprueba la función sino a quienes la llaman, así que una sexta vía que lo olvide hará fallar la suite.
- La rama por defecto era la cadena `main`, fija en el código. sh0 nunca consultaba al remoto: `laravel/laravel` (en `13.x`) y todo repositorio aún en `master` fallaban en el primer paso con un mensaje de libgit2. Una rama vacía significa ahora «la del repositorio»: el clon resuelve el HEAD remoto, escribe el nombre encontrado en la aplicación, y una rama inexistente se informa nombrando las que sí existen.
Guardas que nunca se ejecutaban: CSRF, limitación de tasa y diez comandos de CLI rotos
- `sh0 push` no podía desplegar en absoluto. Once exenciones de CSRF estaban escritas con un prefijo `/api/v1/` que axum ya había retirado: la guarda no coincidía con nada y `/apps/upload` y `/auth/logout` respondían 415. Las exenciones coinciden ahora con las rutas que la capa ve realmente; un despliegue mediante `sh0 push` se midió en 25,7 s.
- `sh0 login` fallaba con `Unexpected response format`. El comando seguía deserializando un token que la API ya no devuelve -- coloca cookies HttpOnly y solo entrega el token CSRF. El inicio de sesión ahora autentica, supera el segundo factor cuando está configurado, acuña una clave de API y la persiste; la clave lleva el nombre del usuario, el de la máquina y la fecha.
- El limitador de tasa global estaba inerte, y el defecto se midió sobre la propia instancia de demostración pública antes de la corrección: 1100 lecturas, 1100 respuestas, ni un solo 429, frente a las 1000 lecturas y 500 escrituras por minuto anunciadas. Misma causa raíz -- la capa está montada dentro del nido `/api/v1`, así que sus rutas `/api/v1/...` nunca coincidían. Es una corrección de seguridad.
- `X-Forwarded-For` solo se cree cuando la petición llega de un par loopback o privado, que es lo que es el propio proceso hijo Caddy de sh0. Nota de compatibilidad: una instalación situada tras un proxy con dirección pública -- Cloudflare y similares -- cuenta ahora todo su tráfico en un único compartimento, a falta de una lista de proxies declarados.
- Ocho comandos `list` estaban rotos -- `database-servers`, `auth-servers`, `realtime-servers`, `function-servers`, `mail`, `file-storage`, `uptime` y `nodes` morían todos con `Failed to parse paginated response`. `sh0 templates info` y `sh0 db connection-info` fallaban por nombres de campo que habían derivado en el servidor. El banner de arranque además anunciaba systemd en macOS, donde el instalador no registra tal servicio; ahora nombra launchd y calla cuando el servidor ya corre bajo un LaunchAgent.
Ocho casos de despliegue jugados en una máquina real, tres muros encontrados
- Esta versión sale de una matriz de humo del despliegue jugada entera en una máquina real -- ocho casos, no una relectura de código. Seis pasan: Node genérico, Next con pnpm, sitio estático, Dockerfile arbitrario, y las plantillas PostgreSQL y Redis. Dos fallaban y siguen abiertos: Laravel y docker-compose.
- El falso verde, y el peor de los tres. La comprobación de salud sondeaba `docker-proxy`, que completa el apretón de manos TCP sea cual sea la salud del contenedor: una aplicación muerta se declaraba sana. La sonda devuelve ahora un estado de tres valores, y es su resultado el que decide, no su fallo. Medido: un `nginx:alpine` sin HEALTHCHECK en un puerto deliberadamente erróneo falla ahora tras 304 738 ms, allí donde la v1.6.20 lo declaraba verde en menos de un minuto.
- Sitios estáticos: nginx moría en bucle por su pidfile. El `chown` no había seguido el traslado del pidfile a `/tmp/nginx`. Corregido, más una prueba que verifica cada ruta escribible individualmente -- la prueba existente solo buscaba la subcadena `chown` y se mantuvo verde durante todo el episodio.
- El puerto introducido sobrescribía en silencio el `EXPOSE` de la imagen. sh0 lee ahora el `EXPOSE` cuando no se indica ningún puerto, y avisa en caso de desacuerdo, en las cinco vías de despliegue.
- pnpm. Las dependencias con scripts de compilación ya no se construían, y la poda de pnpm fallaba dos veces. Criterio de aceptación alcanzado: `ts-nextjs-tailwind-starter` compila en 211 s y sirve un 200.
- 804 pruebas superadas, `clippy --workspace --all-targets -- -D warnings` en verde.
Una retención que respeta las copias manuales y restauraciones que alcanzan los servidores autónomos
- La retención ya no toca las copias manuales. Una programación solo cuenta y purga las copias que ella creó; todo lo que se lanza a mano queda inmune por construcción. La migración 057 vincula cada copia con su programación y solo adopta las filas existentes cuando la atribución es cierta: un origen con varias programaciones conserva intactas sus filas antiguas en lugar de adivinar. Es el cambio de motor anunciado como pendiente en la v1.6.19.
- El modal de programación lista los servidores de base de datos autónomos. La tarjeta Base de datos los contaba, la lista de selección no: un servidor visible en el recuento no podía programarse. Ambos muestran ahora la misma población -- bases de aplicaciones, servicios con base embebida y servidores autónomos con una insignia «DB Server» -- y el paso atrás vuelve a la lista correcta.
- Una restauración externa puede apuntar a un servidor de base de datos autónomo, servidor completo o base única. La vía de servidor completo conserva las bases ya presentes en el destino, la garantía introducida en la v1.6.19. Tres casos se rechazan ahora con un mensaje claro en lugar de fallar en silencio: un servidor sin contenedor iniciado, un nombre de base que empieza por guion y un destino desconocido.
- El estado de restauración de una copia se guarda en el momento de crear su fila. Las restauraciones externas mostraban un estado vacío hasta la primera actualización, una laguna presente desde la inserción original y revelada por las pruebas nuevas. La confirmación de edición de una programación también está traducida en los cinco idiomas del panel en lugar de mostrar su clave sin traducir.
Seguridad de restauración, reparación de filas y un contrato de retención coherente
- Restaurar una copia de servidor PostgreSQL completo ya no destruye el destino. La restauración de v1.6.18 eliminaba todas las bases del servidor de destino y luego no restauraba nada -- una regresión publicada con la corrección de pg_dumpall. La restauración ahora filtra el script en el momento de restaurar: los archivos ya producidos por v1.6.18 siguen siendo restaurables.
- Las copias de MongoDB se autentican. mongodump y mongorestore se lanzaban sin credenciales: ninguna copia MongoDB de un servidor gestionado había producido jamás un archivo -- cada intento moría en el muro de autenticación. La contraseña ahora llega a las herramientas por el entorno de ejecución del contenedor.
- Las copias de servidor completo de CockroachDB se rechazan con un mensaje claro en lugar de fingir. La imagen no incluye herramientas cliente de PostgreSQL, así que la función no puede funcionar; la rama muerta que sugería lo contrario se ha eliminado.
- La migración 056 repara las filas de copia dañadas por versiones anteriores: restauraciones externas registradas como archivos (una ruta sin tamaño) y filas atascadas en « restoring » por la antigua ruta de restauración. Dos invariantes medidos en todo el historial de versiones hacen segura la reparación; las filas inclasificables se dejan intactas y documentadas.
- La retención ya solo tiene un contrato: 7 por defecto en todas partes, 0 significa ilimitado. El formulario decía 30 mientras la API decía 7, y escribir 0 se convertía silenciosamente en 30 porque cero es falsy. Límites 0-365, con etiquetas actualizadas en los cinco idiomas del panel.
- La retención cuenta todas las copias de un origen -- programadas y manuales por igual. La documentación prometía que las manuales nunca se contaban: era falso frente al motor, y la documentación ahora dice lo que ocurre realmente. Hacer inmunes las copias manuales es un cambio futuro del motor, seguido aparte.
Retención de copias y volcados de servidor completo
- La retención de copias de seguridad por fin se ejecuta. La función de purga existía, no se llamaba desde ningún sitio y nunca se había ejecutado desde la v1.0.0: el campo «Retención» del panel no controlaba nada y los repositorios crecían sin límite. Ahora se ejecuta tras cada copia programada correcta, con un barrido horario de recuperación para los repositorios ya desbordados.
- Una copia de un servidor PostgreSQL completo ya contiene sus datos. El planificador pasaba «postgres» como nombre de base de datos, de modo que volcaba la base de arranque, vacía: el archivo estaba bien formado, era restaurable y estaba vacío. Las copias de servidor completo usan ahora pg_dumpall, y la restauración ya no se ejecuta en una sola transacción, porque crear bases de datos lo impide.
- Las copias de un servidor MySQL completo funcionan, sin más. Nunca habían llegado a ejecutarse: el planificador pasaba «--all-databases» como nombre de base de datos, que la validación rechazaba por su guion inicial. Misma causa que el fallo de PostgreSQL, síntoma opuesto: este fallaba ruidosamente en lugar de mentir en silencio.
- El panel decía «Retención (días)» para lo que siempre ha sido un número de copias. Corregido en los cinco idiomas del panel.
- Estas dos correcciones están verificadas por pruebas, todavía no en un servidor real. Ninguna prueba de la suite toca una instancia PostgreSQL auténtica: comprueban el comando construido, nunca su salida. Considere esta versión corregida-pero-no-probada en los volcados de servidor completo hasta que se haya ejecutado en su propia máquina.
Copias de seguridad de bases gestionadas -- activación, programación, restauración
- Una base de datos creada en un servidor de bases gestionado ya se puede respaldar: el disparador solo consultaba la tabla de bases independientes, por lo que una base gestionada respondía «origen de copia no encontrado». Verificado en un servidor real abriendo el artefacto: contiene la tabla y sus filas.
- Las copias de un servidor de bases completo ya se pueden restaurar. El disparador aceptaba un tipo de origen que la restauración no conocía, así que toda restauración de ese tipo se aceptaba y luego fallaba en segundo plano; ahora los destinos inválidos se rechazan de entrada.
- Una restauración externa ya no provoca la purga de copias reales. El registro de una restauración se escribía con el mismo estado «completado» que un archivo, de modo que la retención lo contaba y borraba copias auténticas -- filas y objetos almacenados -- para respetar la cuota. Copias y operaciones de restauración son ahora registros de naturaleza distinta.
- Las bases gestionadas pueden incluirse en una programación de copias, no solo respaldarse bajo demanda.
- Los proyectos Python con Pipfile ya incluyen sus dependencias en la imagen de producción. Comprobado abriendo la imagen construida y no mediante una respuesta HTTP correcta: la corrección anterior pasaba sus pruebas y aun así entregaba una imagen sin ellas.
- Los proyectos con pnpm vuelven a compilar: la imagen generada instala exactamente la versión de pnpm que produjo el archivo de bloqueo, sobre una base Node lo bastante reciente para ejecutarla. Queda un caso abierto: un proyecto pnpm cuyas dependencias ejecutan scripts de instalación falla al compilar; corrección en curso.
Correcciones de compilación en despliegues Git -- gestores de paquetes, Django, sondas de salud
- Los proyectos con yarn o bun vuelven a compilar: la imagen generada instala el gestor de paquetes en lugar de invocar uno que nunca estuvo presente. Los proyectos con pnpm siguen bloqueados: la verificación en condiciones reales mostró que la imagen base de Node es demasiado antigua para la versión de pnpm que se descarga; corregido en 1.6.17.
- Los despliegues Django ejecutan collectstatic en la etapa de producción, donde realmente están las dependencias -- el paso fallaba en silencio y los archivos estáticos devolvían un error 500
- Los proyectos Python con Pipfile aún no están corregidos: la verificación en condiciones reales mostró que la corrección incluida aquí es incompleta -- las dependencias siguen sin llegar a la imagen final. Corregido y verificado en un servidor real en 1.6.17.
- Las sondas de salud en imágenes Alpine consultan 127.0.0.1 con respaldo en IPv6 -- busybox wget resolvía ::1 primero, por lo que los servidores solo IPv4 se reiniciaban como no saludables
- Los proyectos Rust compilan con una cadena de herramientas actual (rust:1-alpine) -- la imagen fijada en 1.77 ni siquiera podía leer un Cargo.lock moderno
Refuerzo de alertas y monitorización -- RBAC, SSRF, servidores de autenticación
- Las reglas de alerta y los canales de notificación ahora aplican los permisos de rol -- los observadores del proyecto ya no pueden crear ni editar alertas, ni leer los secretos de las rutas de notificación
- Las comprobaciones de uptime y de alertas están reforzadas contra SSRF -- las solicitudes salientes ya no pueden dirigirse a direcciones internas o privadas
- El DNS rebinding se neutraliza fijando la IP resuelta durante toda la solicitud, y la monitorización ahora falla de forma explícita si su cliente HTTP reforzado contra SSRF no puede construirse, en lugar de recurrir silenciosamente a uno inseguro
- El aprovisionamiento de servidores de autenticación (Logto) ahora concede solo los roles necesarios y falla de forma explícita ante una creación parcial, en lugar de dejar un servidor a medio crear marcado como listo
- Se eliminaron rutas de notificación muertas y las entradas de configuración de alertas y uptime se validan de forma más estricta
Correcciones de los hubs BaaS -- secretos, dominios, funciones edge
- Las restauraciones de bases de datos ahora reemplazan la base de datos de destino y se revierten de forma atómica ante un error, en lugar de fusionar silenciosamente filas con los datos existentes
- Las credenciales de los servidores realtime solo se devuelven a desarrolladores y roles superiores -- los observadores del proyecto ya no reciben los secretos de conexión
- Los servidores realtime, auth y de funciones ahora son accesibles en sus dominios públicos *.sh0.app
- Los servidores de funciones Deno arrancan de forma fiable -- un arranque fallido se informa de inmediato en lugar de mostrar un falso estado de ejecución
- Los servidores de funciones obtienen un dominio público operativo con HTTPS automático al crearse
Paridad de ejecución de contenedores -- correcciones de fiabilidad
- Restauración externa corregida -- restaurar una copia de seguridad almacenada en un destino externo (S3, R2) ahora lee correctamente el artefacto subido
- Paridad de previews -- los contenedores de preview ahora se ejecutan con el mismo usuario que en producción, de modo que las aplicaciones que requieren privilegios elevados ya no fallan en bucle en las previews
- Paridad de escalado -- las réplicas ahora heredan el usuario del contenedor principal, de modo que escalar una aplicación cuya imagen se ejecuta como root ya no produce réplicas que fallan en bucle
- Correcciones de plantillas -- Garage, Logto y Plane ahora arrancan correctamente desde la instalación
Refuerzo de copias de seguridad y almacenamiento
- Restauración corregida -- restaurar una copia de seguridad de base de datos o de volumen desde el panel o la API ahora se completa correctamente
- Control de acceso de copias -- listar, lanzar, descargar, restaurar y eliminar copias de seguridad ahora exige los permisos adecuados del proyecto
- Credenciales protegidas -- los endpoints de almacenamiento de archivos ya no devuelven credenciales de administrador compartidas, y los destinos de copia de seguridad solo pueden gestionarlos sus propietarios
- Listados acotados -- los dominios de almacenamiento y las claves de acceso solo son visibles y gestionables dentro de tus propios proyectos e instancias
- Limpieza completa -- eliminar una copia de seguridad borra su artefacto almacenado, y eliminar una instancia de almacenamiento retira sus rutas de proxy y su configuración TLS
Fiabilidad de despliegues -- correcciones complementarias
- Despliegues Git accesibles -- ahora se recuerda el puerto detectado de una aplicación, por lo que los proyectos Next.js, Django, FastAPI y Rust responden en su URL de vista previa sin configuración manual
- TLS más limpio -- el servidor de origen ya no reintenta certificados que no puede obtener para dominios proxy *.sh0.app, liberando la cuota de certificados compartida
- Plausible Analytics -- la plantilla ahora crea el rol y la base de datos PostgreSQL, de modo que la pila arranca correctamente
- Zitadel -- la plantilla ahora incluye una pantalla de inicio de sesión funcional de fábrica
- Convex -- el backend ya arranca (marcado como experimental mientras se completa el soporte multipuerto)
- Limpieza mejorada -- los despliegues fallidos ya no dejan contenedores ni imágenes huérfanos
Refuerzo de producción -- lote de correcciones de la auditoría
- Las stacks populares se despliegan correctamente -- las aplicaciones reciben su cabecera Host real, por lo que WordPress, Laravel y Django funcionan detrás de los dominios *.sh0.app
- Estado de despliegue fiable -- los contenedores en bucle de reinicio se detectan y se informan como fallidos en lugar de mostrarse como en ejecución
- Indicador SSL preciso -- los dominios muestran el estado real de su certificado y los enlaces usan HTTPS
- Valores predeterminados más seguros -- los paneles de administración secundarios (consolas de base de datos, almacenamiento de objetos, proveedores de identidad) ya no se exponen públicamente de forma predeterminada
- Next.js y Rust -- los proyectos estándar de create-next-app y los proyectos Rust reales ahora se despliegan sin configuración manual
- Reparaciones del catálogo de plantillas -- se corrigió la gestión de credenciales de Zitadel, Chatwoot, Langfuse, SurrealDB y Convex; se eliminaron las plantillas cuyas imágenes de origen ya no están disponibles
sh0 Manager: gestión de la flota desde el móvil
- Aplicación móvil sh0 Manager: gestiona todas tus instancias sh0 desde el teléfono (iOS y Android)
- Vinculación por código QR: escanea desde el panel para vincular instancias, con tokens seguros de duración limitada
- Vista de flota: todas las instancias, su estado en línea o desconectado, número de aplicaciones y plan, de un vistazo
- Autenticación por token Bearer: la aplicación móvil usa autenticación de sesión mediante la cabecera Authorization
- Sección Manager en el panel: genera tokens de vinculación, consulta la información de la instancia y gestiona su propiedad
Registros de construcción en directo, variables de entorno al subir y fiabilidad
- Registros de construcción en directo: sigue las construcciones Docker en tiempo real, con desplazamiento automático
- Corregida la condición de carrera al subir variables de entorno: se guardan de forma atómica antes de iniciar el despliegue
- Tiempo límite de construcción ampliado a 30 minutos: admite Rust y otros proyectos de compilación larga
- Mayor precisión de la puntuación de salud: tope de penalización por regla, reglas de seguridad ya no bloqueantes
- 0cron.dev desplegado con éxito en sh0 (backend en Rust y frontend SvelteKit): la primera aplicación Rust real
- Eliminado el ruido de los registros de latido: registros rutinarios en nivel depuración, información solo al cambiar la IP
Dominios de vista previa: una URL inmediata para cada aplicación
- Cada instancia sh0 se registra al arrancar en el proxy en la nube, sin ninguna configuración
- Formato de subdominio plano: undefined-undefined.sh0.app — un único certificado comodín, sostenible más allá de 100 000 instalaciones
- Proxy inverso de los dominios de vista previa: un middleware Axum encamina el tráfico al contenedor Docker correcto
- No hace falta ningún registro DNS en Cloudflare: el comodín *.sh0.app basta
- El panel muestra una etiqueta «Vista previa» y enlaces HTTPS pulsables para todos los dominios de vista previa
- Funciona en el plan gratuito: los dominios de vista previa no requieren licencia
Ronda de QA 1: correcciones y acabado
- Corregida la etiqueta de estado SSL que mostraba «pendiente» cuando HTTPS ya estaba activo
- DNS del correo: el registro PTR pasa a ser opcional (una IP compartida no permite DNS inverso)
- URLs del correo: eliminados los puertos Docker aleatorios, extremos HTTPS limpios a través del proxy Caddy
- Añadidas redirecciones /webmail y /admin al estilo de cPanel para los nombres de host del correo
- Corregido el bucle infinito de recarga del navegador en la pestaña Cola del correo
- Las credenciales de administración del correo se muestran en la pestaña Resumen, con conmutador de visibilidad
- Tareas programadas: se eliminan automáticamente las redirecciones de shell (> /dev/null 2>&1) de los comandos
- El historial de ejecución de tareas muestra la salida estándar y de error en un visor desplegable
- Disparo de una tarea: ventana en tiempo real con sondeo, en lugar de un aviso silencioso
- Corregido el servidor de autenticación: imagen Docker correcta (svhd/logto), punto de entrada adecuado, base de datos inicializada en el primer arranque
- Autenticación, tiempo real y funciones: estados vacíos con explicaciones y requisitos previos
- Los errores internos devuelven ahora su mensaje real (producto autoalojado, el usuario es administrador)
- Terminal del servidor y explorador de archivos en Ajustes, para acceso directo a la máquina
- Pestañas Archivos y Volúmenes añadidas a las páginas de detalle de los servidores de funciones y de tiempo real
- Corregida la restricción de dominio sobre service_id (migración 049)
- 475 nuevas claves de internacionalización y 4 páginas del sitio convertidas a Paraglide
Seguridad, Pulido y Funcionalidad Completa
- Funciones avanzadas de correo: configuración de filtro antispam, respuesta automática de vacaciones, reglas de filtro Sieve, monitoreo de cola de correo
- Rotación de claves DKIM y streaming de registros de contenedores para servidores de correo
- Restricción por licencia: todos los servicios BaaS restringidos a Pro+ con ventanas emergentes UpgradePrompt en 12 páginas
- Integración de reseñas de Trustpilot como pestaña fija en todas las páginas del panel de control
- Estadísticas rápidas de BaaS en la página principal del panel de control
- 8 nuevas páginas SEO de alternativas: Vercel, Supabase, Firebase, Netlify, cPanel, Render, Railway, Fly.io
- Rediseño de la página de inicio con héroe BaaS, sección de capacidades y franja de precios
- Matriz comparativa de características en la página de precios con 27 filas
- Página de relaciones con inversores con documentos PDF de libro blanco y presentación
- Prompts del sistema de IA actualizados con las funciones y capacidades actuales
- 979 claves i18n para páginas SEO en 5 idiomas
- 5 correcciones de seguridad críticas: inyección Sieve, pérdida de datos en respuesta automática de vacaciones, bypass de alcance MCP en 92 herramientas, traversal de ruta en copias de seguridad, sobrescritura de estado de Cloudflare
- 10 correcciones de seguridad importantes: validación de entrada, limpieza de DNS, validación de destino de sandbox, mensajes de confirmación en CLI
Almacenamiento de Archivos, Servidores de Bases de Datos y Correo
- Almacenamiento de objetos compatible con S3 gestionado, impulsado por MinIO -- buckets, claves de acceso, monitoreo de uso
- Servidores de bases de datos independientes: PostgreSQL, MySQL, MariaDB, MongoDB, Redis con gestión de usuarios y permisos
- Alojamiento de correo gestionado mediante Stalwart con configuración automática de DKIM, SPF y DMARC
- Asistente de configuración DNS en 4 pasos para correo con soporte de autoconfiguración de Cloudflare
- Buzones, alias, reglas catch-all y monitoreo de entregabilidad
- Integración de interfaz de administración de bases de datos: dbGate, phpMyAdmin, Mongo Express
- Acceso externo a bases de datos con lista blanca de IP para conexiones remotas seguras
- Página de dominios global: vista centralizada de todas las URL de servicios de cada aplicación
- Más de 50 nuevos endpoints de API para almacenamiento de archivos, servidores de bases de datos y correo
- Funciona de inmediato con AWS SDK, Laravel, WordPress y cualquier cliente compatible con S3
Infraestructura central
- Workspace Cargo con 10 crates de Rust, gestión de dependencias compartida
- sh0-db: SQLite con modo WAL, pool r2d2, 30 migraciones
- sh0-docker: cliente completo de la API de Docker Engine sobre socket Unix (hyper 1.x)
- sh0-api: servidor REST Axum con CRUD, paginación, streaming de logs WebSocket
- sh0-git: Git clone/pull (libgit2), parsing de webhooks GitHub/GitLab/Bitbucket con HMAC-SHA256
- sh0-builder: 19 detectores de stack, 15 plantillas Dockerfile, builds multi-etapa
- Motor de verificación de salud del código: 34 reglas en Rust puro en 8 categorías
Proxy inverso y pipeline de despliegue completo
- sh0-proxy: gestión de proceso hijo Caddy con API admin JSON
- Auto-SSL vía Let's Encrypt con correo ACME configurable
- Pipeline de despliegue de extremo a extremo: git pull -> analizar -> construir -> desplegar -> verificación de salud -> enrutar
- Intercambio de contenedores blue-green con despliegue sin tiempo de inactividad
- Sistema de limpieza Docker: imágenes colgantes, imágenes antiguas de apps, poda de caché de build
- Verificación de espacio en disco pre-despliegue (falla a >90%, advierte a >80%)
- Rollback vía reutilización de imagen en caché
Auth y monitoreo
- Hashing de contraseñas Argon2id, JWT HS256 (1h acceso + rotación de refresh de 30d)
- 2FA TOTP con códigos de respaldo hasheados y URI de provisión
- Sistema de claves API: hasheadas con SHA-256, prefijo sh0_, comparación en tiempo constante
- Clave maestra de cifrado AES-256-GCM (PBKDF2, 100K iteraciones)
- Recolección de métricas en tiempo real: CPU, memoria, I/O de red por contenedor
- Evaluación de alertas: high_cpu, high_memory, app_down con enfriamiento de 5 min
Motor de respaldos y panel de control
- Volcados de base de datos vía Docker exec: pg_dump, mysqldump, mongodump
- Respaldo de volúmenes (tar + gzip) con cifrado AES-256-GCM
- Programación de respaldos basada en cron con poda de retención
- SvelteKit 2 + Svelte 5 runes SPA con TailwindCSS 4
- Tema claro/oscuro, i18n de 5 idiomas (EN, FR, ES, PT, SW)
- Cliente API con token Bearer automático, WebSocket con reconexión automática
- Panel integrado en binario Rust vía include_dir + build.rs
Panel de control central y páginas extendidas
- Página de detalle de app con diseño de 6 pestañas: Resumen, Despliegues, Logs, Dominios, Entorno, Configuración
- Visor de logs en tiempo real: WebSocket, estilo terminal, auto-scroll, buffer de 1000 líneas
- Editor de variables de entorno con cifrado AES-256-GCM/toggle de revelación
- Página de gestión de bases de datos con selector de motor (postgres, mysql, mongodb, redis, mariadb)
- Gestor de respaldos: activar, restaurar, eliminar, creación de programación con cron
- Página de monitoreo: medidores de CPU/memoria, CRUD de alertas, actualización automática
- Configuración: info del servidor, configuración/desactivación de 2FA TOTP, gestión de claves API
CLI, plantillas, alertas y Compose
- Cliente CLI: 7 comandos (apps, deploy, logs, env, check, ssh, status)
- Verificación de salud del código local vía sh0 check con salida de terminal a color
- 170 plantillas YAML de un clic en 15 categorías (de WordPress a Ollama)
- Motor de sustitución de variables con autogeneración para secretos/contraseñas
- 5 canales de despacho de alertas: correo (SMTP), Slack, Discord, Telegram, webhook
- Parser Docker Compose v3 con despliegue multiservicio
RBAC, exportación, cron, vistas previas y hooks
- RBAC de 4 niveles: Owner > Admin > Developer > Viewer (global + por proyecto)
- Registro de auditoría en todos los handlers (fire-and-forget asíncrono)
- 7 formatos de exportación: Docker Compose, Kubernetes, AWS ECS, GCP Cloud Run, Vercel, Railway, Render
- Programador de trabajos cron con ejecución basada en ticks, captura stdout/stderr, historial de ejecuciones
- Entornos de vista previa: autodespliegue basado en PR con subdominios únicos y limpieza TTL
- Hooks de despliegue: pre_build, post_build, pre_deploy, post_deploy con cumplimiento de timeout
- sh0.yaml Infraestructura como código: define stacks completos en un archivo
Escalado y monitoreo de disponibilidad
- Escalado horizontal: 1-50 réplicas con balanceo de carga (round_robin, least_conn, random)
- Autoescalado por umbrales de CPU/memoria con enfriamientos configurables
- Monitoreo de disponibilidad: verificaciones de salud HTTP con detección de incidentes y ciclo de vida
- Páginas de estado públicas con historial de disponibilidad por dominio
- Sistema de suscripción por correo para notificaciones de página de estado
51 problemas encontrados y corregidos
- 2 auditorías de seguridad exhaustivas en las 25 fases
- 13 correcciones críticas: comparación de claves API en tiempo constante, auth JWT en WebSocket, hashing de códigos de respaldo, bloqueo de despliegue por app
- 20 correcciones altas: validación de dominios, prevención de path traversal, redacción de secretos en logs de build, argumentos Docker codificados en URL
- Expiración JWT reducida (7d -> 1h) con rotación de token de refresh de 30 días
- Protección CSRF (cumplimiento de Content-Type + patrón double-submit)
- Limitación de tasa: login (10/15min), TOTP (5/5min), global (1000/500s)
- Encabezados de seguridad: HSTS, CSP, X-Frame-Options, X-Content-Type-Options
Arquitectura basada en stacks y pulido
- Barra lateral de solo íconos de 56px con tooltips + barra lateral de contexto de 240px para navegación de proyectos
- Arquitectura basada en stacks: agrupa servicios por proyecto (frontend + backend + bd + caché)
- Deploy Hub: asistente unificado con 183 opciones de despliegue, pestañas de categoría, sección destacada
- 7 componentes de formulario de despliegue: FormGit, FormUpload, FormDockerImage, FormDockerfile, FormCompose, FormService, FormFramework
- Paleta de comandos Cmd+K: busca páginas, stacks y servicios al instante
- Barra lateral de contexto responsiva para móvil con cajón + botón hamburguesa
- Rediseño de página principal con estadísticas del servidor, cuadrícula de stacks, acciones rápidas
- Vista de detalle de app con 16 pestañas: Resumen, Despliegues, Logs, Terminal, Archivos, Almacenamiento, Dominios y SSL, Entorno, Redirecciones, Vistas previas, Hooks, Escalado, Disponibilidad, Cron, Servicios, Configuración
Imagen Docker, Dockerfile, ZIP y PHP/Ruby/.NET
- Despliegue directo de imagen Docker: descargar imagen, saltar pipeline git/build
- Despliegue solo Dockerfile: pegar contenido, construir localmente
- Despliegue por carga de archivo ZIP con límite de 500 MB y prevención de path traversal
- Plantillas Dockerfile para PHP, Ruby y .NET agregadas
- Nombres de apps por proyecto (índice único compuesto)
- Nomenclatura de contenedores con prefijo de proyecto: sh0-undefined-undefined
- 45 nuevas pruebas (escalado, compose, YAML)
Plantillas, terminal, explorador de archivos, volúmenes
- Página Deploy Hub con catálogo de 183 opciones de despliegue
- Barra de progreso de despliegue con seguimiento de pasos en logs
- 170 plantillas: bases de datos (33), CMS (18), analítica (7), auth (6), IA/ML (8), DevTools (12) y más
- Gestión de subservicios (contenedores MySQL, phpMyAdmin, dbGate)
- URLs de acceso a servicios: endpoints internos/locales/externos con toggle externo
- Terminal web: xterm.js con selector de shell (sh/bash/ash), soporte SSH TTY
- Explorador de archivos: explorador de dos paneles estilo Docker Desktop con editor en línea
- Almacenamiento persistente: gestión de volúmenes Docker, montajes bind, montajes de archivos
- Página de documentación API con playground interactivo (26 grupos de endpoints)
URLs de conexión, credenciales, variables de entorno masivas
- URLs de conexión de base de datos: internas y externas, calculadas automáticamente desde la configuración del contenedor
- Tarjeta de credenciales de base de datos: usuario, contraseña, cadenas de conexión
- Operaciones masivas de variables de entorno con modo editor .env
- Persistencia de credenciales de plantilla (variables de entorno almacenadas en BD)
Certificados SSL, fiabilidad de Caddy, proveedores de almacenamiento
- Migración a cookies HTTP-only con patrón CSRF double-submit (SameSite=Strict)
- Autogeneración de clave maestra (derivada del secreto JWT en el primer arranque)
- Certificados SSL personalizados: generación de CSR (rcgen), carga de PEM (x509-parser), ssl_mode por dominio
- Cifrado de clave privada (AES-256-GCM) con permisos de archivo restringidos (0o600)
- Fiabilidad del proxy Caddy: eliminar procesos obsoletos, reintentar cargas de configuración, sincronización de rutas de BD
- 13 proveedores de almacenamiento vía OpenDAL: S3, R2, Wasabi, Backblaze B2, SFTP, FTP/FTPS, Dropbox, Google Drive y más
- Corrección de IPv6 para FTP/FTPS (modo EPSV, cliente suppaftp directo)
- Alineación de planes/precios: Free ($0), Pro ($19/mes), Business ($97/mes)
CronBuilder, redirecciones, restauración de respaldo, refactorización de monitoreo
- Componente CronBuilder con 18 presets y sincronización bidireccional
- Reglas de redirección de URL: coincidencias exactas, de prefijo y regex con códigos de estado 301/302/307/308
- Restauración de respaldo: Flujo A (respaldos sh0) y Flujo B (carga de fuente externa)
- Refactorización de página de monitoreo: panel de 4 pestañas (Resumen, Apps, Disponibilidad, Alertas)
- Reducción de falsos positivos en verificación de salud (más de 80 nuevas pruebas, omitir archivos env/lock/doc)
- Modal de configuración DNS con IP real del servidor y guía de Cloudflare
- Configuración de correo ACME (almacenado en BD, actualizaciones en tiempo de ejecución)
BYOS multiservidor
- Registro de nodos remotos con gestión de túneles SSH (russh)
- SSH TOFU (Trust on First Use) con verificación de huella digital de clave del host
- Transferencia de imágenes Docker vía save/load sobre túneles SSH
- Pipeline de despliegue consciente de nodos que despacha builds a servidores remotos
- Panel de gestión de nodos con indicadores de estado y monitoreo de salud
- Refuerzo de nodos: manejo de errores, validación de conexiones, limpieza elegante
Servidor MCP y asistente de IA
- Servidor MCP con 103 herramientas: transporte Streamable HTTP en /mcp (JSON-RPC 2.0)
- Generación de herramientas basada en OpenAPI vía utoipa con extensiones x-mcp-*
- Seguridad de 3 niveles: alcances de clave API (read/standard/admin), clasificación de riesgo por herramienta, tokens de confirmación para operaciones destructivas
- Gateway de IA: enrutamiento de chat de 3 vías (conector MCP, heredado, experto en docs)
- AI Sandbox: contenedor sidecar Alpine 3.19 por app con shell root, instalación de paquetes, volúmenes escribibles
- Integración de Claude MCP Connector para ejecución agéntica de herramientas del lado del servidor
- Chat de IA en el panel con selector de modelo, historial de conversaciones, línea de tiempo de pasos de procesamiento
- Modal de capacidades: 24 capacidades en 5 categorías, traducido en 5 idiomas
- Facturación con billetera prepago con precios por token (Haiku, Sonnet, Opus)
- Soporte BYOK en plan Business (claves API de Anthropic u OpenRouter)
- 10 rondas de auditoría en 5 fases -- 0 problemas críticos llegaron a producción
Nivel Gratuito, Docker y Distribución
- Copias de seguridad disponibles en el plan Gratuito (almacenamiento local); almacenamiento en la nube reservado para Pro+
- Imagen Docker publicada en Docker Hub (zerosuiteinc/sh0) y GHCR
- Sistema de autoactualización: sh0 update verifica GitHub Releases y actualiza en el lugar
- Configuración automática del servicio systemd en Linux (sh0 serve instala y habilita la unidad)
- Bloqueadores de página completa reemplazados por banners integrados en monitoreo, copias de seguridad y equipo
- Matriz de características de licencia refinada: copias de seguridad granulares (local/nube) y monitoreo (métricas/alertas/uptime)
- Comando de desinstalación: sh0 uninstall elimina limpiamente el binario, la unidad systemd y los datos
- Banner de inicio con versión, URL del panel de control y consejo de systemd
Todo en v1.0.0
Motor de despliegue
- 5 pipelines de despliegue: Git, imagen Docker, Dockerfile, carga ZIP, plantilla/Compose
- 19 autodetecciones de stack con 15 plantillas Dockerfile optimizadas
- Despliegues blue-green con intercambio sin tiempo de inactividad y rollback
- 183 opciones de despliegue en el Deploy Hub
- Parser Docker Compose v3 con despliegue multiservicio
Tienda de plantillas
- 170 plantillas de un clic en 15 categorías
- Bases de datos, CMS, IA/ML, DevTools, analítica, auth, correo, colas, búsqueda
- Sustitución de variables con autogeneración (secretos, contraseñas)
- Despliegue multiservicio con ordenamiento topológico
Dominios y SSL
- Auto-SSL vía Let's Encrypt con Caddy ACME
- Carga de certificados SSL personalizados con generación de CSR
- Reglas de redirección de URL (prefijo, exacto, regex)
- Balanceo de carga: round_robin, least_conn, random
Monitoreo y alertas
- Métricas en tiempo real de CPU, memoria y red con gráficos sparkline
- 5 canales de alerta: correo, Slack, Discord, Telegram, webhook
- Monitoreo de disponibilidad con páginas de estado públicas
- Autoescalado por umbrales de CPU/memoria (1-50 réplicas)
Respaldo y almacenamiento
- Volcados de base de datos (pg_dump, mysqldump, mongodump) + respaldos de volúmenes
- Cifrado AES-256-GCM con respaldos programados basados en cron
- 13 proveedores de almacenamiento vía OpenDAL (S3, R2, SFTP, Dropbox, Google Drive)
- Restauración desde respaldo o almacenamiento externo
Seguridad
- 51 problemas de seguridad encontrados y corregidos en 2 auditorías
- Contraseñas Argon2id, JWT + rotación de refresh, 2FA TOTP, Google OAuth
- Cifrado AES-256-GCM para todos los secretos (variables de entorno, tokens, claves)
- Prevención de CSRF y SSRF, limitación de tasa, refuerzo de contenedores
Experiencia del desarrollador
- Terminal en el navegador (xterm.js) con selección de shell
- Explorador de archivos con editor en línea, mkdir, eliminar
- Verificación de salud del código: más de 34 reglas escaneadas antes de cada build
- Exportación a 7 plataformas: K8s, AWS, GCP, Vercel, Railway, Render, Compose
Panel de control
- 22 páginas, más de 70 componentes, vista de detalle de app con 16 pestañas
- Paleta de comandos Cmd+K, tema claro/oscuro, 5 idiomas
- Arquitectura basada en stacks con barra lateral doble
- Documentación API con playground interactivo (26 grupos de endpoints)
Automatización
- Trabajos cron con CronBuilder (18 presets, 50 trabajos/app)
- Hooks de despliegue: pre_build, post_build, pre_deploy, post_deploy
- Entornos de vista previa desde webhooks de PR con limpieza TTL
- Infraestructura como código vía sh0.yaml
Equipo y RBAC
- 4 niveles de roles: Owner, Admin, Developer, Viewer
- Control de acceso por proyecto
- Registro de auditoría en todas las operaciones
- Sistema de licencias: Free, Pro ($19/mes), Business ($97/mes)
Asistente de IA
- Servidor MCP con 103 herramientas (37 lectura, 44 escritura, 16 destructivas, 5 sandbox, 1 confirmación)
- AI Sandbox: contenedor Alpine por app para depuración y desarrollo
- Conéctate desde Claude Desktop, Cursor o cualquier cliente MCP
- Gateway de IA con chat web, selección de modelo, historial de conversaciones
- Billetera prepago con opción BYOK en plan Business
En números
Crates de Rust
Migraciones
Endpoints API
Páginas del panel
Componentes UI
Idiomas
Plantillas de despliegue
Herramientas MCP
Reglas de salud
Formatos de exportación
Proveedores de almacenamiento
Canales de alerta
Pruebas aprobadas
Prototipo heredado (Python/FastAPI)
El sh0 original, construido en Python. Arquitectura basada en agentes con detección de stack, verificaciones de salud y generación de Dockerfile. Sirvió como plano para la reescritura en Rust.
¿Por qué Rust? Se reescribió en Rust por: ~30 MB de memoria en reposo (vs ~500 MB en Python), distribución de binario único, API directa de socket Docker (sin shell de CLI), cero pausas de GC bajo carga.
¿Listo para desplegar?
Instala sh0 en menos de 60 segundos y despliega tu primera aplicación.