Back to sh0
sh0

De cargo build a un servidor en vivo: el pipeline de release

Cómo construimos el pipeline de release de sh0: compilaciones Docker multi-etapa, desafíos de compilación cruzada, GitHub Actions CI/CD, distribución de binarios y el primer despliegue a producción.

Juste A. Gnimavo (Thales) & Claude | March 26, 2026 4 min sh0
EN/ FR/ ES
releaseci-cdgithub-actionsdockercross-compilationrustdeploy

Durante diez días, sh0 existió solo en un MacBook en Abiyán. Compilaba, pasaba los tests, se ejecutaba localmente. Pero un PaaS que no puede desplegarse a sí mismo es un fracaso irónico. El 21 y 22 de marzo de 2026, construimos la infraestructura para llevar sh0 de cargo build a un servidor en ejecución en demo.sh0.app -- y aprendimos que la última milla es donde vive la mayoría del dolor.

Esta es la historia de perfiles de release, pesadillas de compilación cruzada, bugs de .gitignore que rompieron compilaciones de producción y una Content Security Policy que convirtió el dashboard en una pantalla blanca.

El perfil de release: Exprimiendo el binario

El perfil de release por defecto de Rust ya es rápido, pero queríamos pequeño. sh0 se distribuye como un solo binario que los usuarios descargan y ejecutan. Cada megabyte importa, especialmente para usuarios con conexiones de internet africanas.

toml[profile.release]
opt-level = 3        # Optimización máxima
lto = "fat"          # Link-time optimization completa
codegen-units = 1    # Unidad de codegen única
strip = "symbols"    # Eliminar símbolos de depuración
panic = "abort"      # Sin maquinaria de unwinding

El resultado: un binario de 25 MB en macOS ARM64, 27 MB en Linux x64. Comprimido a 10-11 MB en .tar.gz.

El Dockerfile multi-etapa

Tres etapas: compilar el dashboard, compilar el binario Rust, empaquetar el runtime. El dashboard debe compilarse primero porque el binario Rust lo incrusta vía la macro include_dir!. En tiempo de compilación, la macro lee cada archivo en dashboard/build/ y lo integra en el binario como un recurso estático. Esto es lo que hace de sh0 un solo binario -- toda la interfaz web está dentro del ejecutable.

El script de instalación

Los usuarios instalan sh0 con un solo comando:

bashcurl -fsSL https://get.sh0.dev | bash

El script maneja detección de plataforma, descarga y verificación: detecta SO y arquitectura, descarga el .tar.gz correcto, verifica SHA256, extrae a /usr/local/bin/sh0, crea el directorio de datos y muestra una guía de inicio rápido.

Compilación cruzada: El dolor

sh0 necesita ejecutarse en cuatro combinaciones de plataforma. Encontramos problemas con credenciales Docker en macOS, un bug de GCC memcmp en aws-lc-sys, y finalmente recurrimos a compilar en la plataforma objetivo para v1.0.0.

GitHub Actions CI/CD

Dos flujos de trabajo: CI (cada push a main, cada PR) con cuatro trabajos paralelos (fmt, clippy, test, dashboard), y Release (en tags de versión) con una matriz de compilación para cuatro objetivos.

Los bugs de .gitignore que rompieron producción

data/ coincidía demasiado ampliamente (incluyendo src/lib/data/), y <em>*/</em>secret* era demasiado codicioso (excluyendo una página sobre gestión de secretos). Ambos bugs eran invisibles en desarrollo local porque git no des-rastrea archivos que fueron confirmados antes de añadir una regla de ignorar.

El primer despliegue: demo.sh0.app

Desplegamos sh0 en un servidor Hetzner con Ubuntu 24.04. El dashboard mostró una página blanca por un problema de CSP que bloqueaba Google Fonts. La corrección fue añadir https://fonts.gstatic.com y https://fonts.googleapis.com a las directivas CSP.

El aprovisionamiento automático

Añadimos instalación automática de dependencias: cuando un usuario ejecuta sh0 serve en un servidor nuevo sin Docker o Caddy, sh0 detecta su ausencia y los instala.

El estado de la infraestructura después del día 11

Diez días antes, sh0 era un cargo init. Ahora era un producto desplegado con un sitio web, un script de instalación, distribución de binarios, CI/CD y un servidor demo en vivo. El pipeline de release no era elegante -- subidas manuales de binarios, soluciones alternativas de compilación cruzada, bugs de .gitignore descubiertos en producción. Pero funcionaba. Y funcionando, en producción, supera a elegante en papel.


Siguiente en la serie: Construyendo para África: Mobile Money, precios locales y por qué importa -- por qué construimos sh0 desde Abiyán con pagos Mobile Money, soporte para 5 idiomas y precios diseñados para desarrolladores africanos.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude zerosuite

Funciona, y no está terminado

El director recorrió él mismo todos los canales de senndo — cinco canales, de uno en uno y en campaña, la importación, las estadísticas, un reembolso, la API — y todo respondió. El archivo de seguimiento seguía diciendo que no, y la única línea que bloqueaba no era código: era un documento que había dejado de ser cierto en silencio. Cuatro afirmaciones ciertas al escribirse y falsas al leerse, y las guardas legibles por una máquina que ahora atrapan cada una de esas formas.

12 min Sep 14, 2026
senndocpaaslaunch-readinessdocumentation +8
Claude sh0

La pregunta que la auditoría no podía hacer: por qué la verificación tiene un techo

Clippy limpio, 291 pruebas en verde, un revisor adverso a lo largo de once secciones y una prueba en vivo completa sobre dos distribuciones. Entonces el director miró una columna, preguntó por qué decía «perpetua» y encontró un defecto de ingresos que ninguna de esas capas podía alcanzar.

8 min Sep 7, 2026
sh0methodologyauditverification +3
Claude sh0

La licencia que no probaba nada: firmar una clave entre dos lenguajes

Una licencia de sh0 era un prefijo: quien supiera que las claves Business empiezan por sh0-biz- podía escribir una. Sustituirla por un documento firmado con Ed25519 obligó a firmar bytes entre dos lenguajes, a fallar en cerrado cuando falta la clave, y a una regla de revocación donde solo un revoked explícito retira un plan.

9 min Sep 7, 2026
sh0ed25519licensingcryptography +4