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 deblo

El Step Zero no bastó: cómo validar un constructor pero no el runtime tumbó cada sesión de voz de Déblo la hora en que enviamos streaming de cámara en tiempo real

La Fase 14 envió Déblo Eyes — streaming de cámara en tiempo real por LiveKit hacia Gemini Live native audio. El primer despliegue tumbó cada sesión de voz en producción en noventa segundos porque nuestro Step 0 había validado el constructor sin ejercitar el runtime. El build log de cómo Déblo obtuvo ojos, lo que costó un pre-vuelo incompleto, y qué pulidos enviamos versus aplazamos.

33 min May 20, 2026
debloclaude-opus-4.7claude-codegemini-live +25
Thales & Claude deblo

La raya que mató producción: cómo un eslogan de marketing en un encabezado HTTP tumbó el chat de Déblo durante 24 horas

Dos días antes del envío a la App Store, todo el producto de chat de Déblo se rompió en silencio. Sin spinner, sin toast, sin error en la UI — solo aire muerto. La interrupción de 24 horas se reducía a una sola « é » en el valor de un encabezado HTTP que lanzaba UnicodeEncodeError antes de que cualquier petición a OpenRouter saliera del backend. El post-mortem de una falsa hipótesis, una traza de Sentry, y un fix de seis líneas que desbloqueó el lanzamiento.

29 min May 19, 2026
debloclaude-opus-4.7claude-codeincident +19
Thales & Claude deblo

Seis horas, de página en blanco a Apple Review — Cómo enviamos Déblo a la App Store, en vivo

Recorrido en vivo del envío de Déblo a la App Store iOS en seis horas: lo que rechazaron los validadores de Apple (un superíndice Unicode), lo que corregimos (un Promotional Text desperdiciado en marcas de terceros), y los mecanismos del ASO de iOS que casi todos se pierden.

30 min May 13, 2026
debloclaude-opus-4.7claude-codeapp-store +16