Arquitectura
Un proceso, un binario
Sección titulada «Un proceso, un binario» ┌──────────────────────────────────┐ │ Pier (single binary) │ │ │ Browser ───────▶ │ Axum ──▶ API routes (100+) │ │ │ │ │ ├──▶ MiniJinja ──▶ HTML (HTMX) │ │ ├──▶ Bollard ──▶ Docker Engine │ │ ├──▶ rusqlite ──▶ SQLite │ │ └──▶ reqwest ──▶ Remote Agents │ └──────────────────────────────────┘ │ ┌───────────────┴────────────────┐ │ Traefik (reverse proxy) │ │ Let's Encrypt · Auto-routing │ └────────────────────────────────┘Componentes
Sección titulada «Componentes»| Capa | Crate | Función |
|---|---|---|
| HTTP + WebSocket | axum | Endpoints de API y flujos SSE/WebSocket para registros y métricas |
| Docker | bollard | Todas las operaciones de contenedores, volúmenes y redes |
| Base de datos | rusqlite | SQLite embebido, modo WAL para lecturas concurrentes |
| Plantillas | minijinja | HTML renderizado en el servidor para el panel de control |
| Autenticación | axum-login + totp-rs | Sesiones opacas por cookie; 2FA con TOTP y códigos de recuperación |
| SSH | russh | Aprovisionamiento de servidores remotos |
| Git | gix | Clone y pull para el despliegue desde Git |
| Métricas | sysinfo | Métricas del sistema y de los contenedores |
| Caché | moka | Caché en memoria para las estadísticas de Docker |
| Runtime | tokio | E/S asíncrona |
Panel de control
Sección titulada «Panel de control»La interfaz se renderiza en el servidor con MiniJinja. HTMX gestiona las actualizaciones parciales; Alpine.js cubre el estado del lado del cliente para interacciones pequeñas (modales, conmutadores). El total de JS del lado del cliente ronda los 30 KB. Todo se entrega embebido en el binario: sin CDN, sin fuentes externas, sin bundler en tiempo de ejecución.
Distribución del almacenamiento
Sección titulada «Distribución del almacenamiento»/opt/pier/├── bin/pier # the binary├── bin/pier.old # previous version (for rollback)├── .env # PIER_SECRET — AES-256 key for env vars└── data/ ├── pier.db # SQLite main database ├── pier.db-wal # WAL file ├── backups/ # automated DB + .env backups └── traefik/ # dynamic config files per domainSeguridad en reposo
Sección titulada «Seguridad en reposo»Cada variable de entorno almacenada en la base de datos se cifra con AES-256-GCM. La clave proviene de PIER_SECRET (32 bytes aleatorios, codificados en base64): systemd la lee desde /opt/pier/.env, y si la variable no está definida, Pier persiste en su lugar un archivo .pier-secret en el directorio de datos. La base de datos por sí sola es inútil sin la clave: la separación es intencional, de modo que un volcado SQL filtrado no filtre los secretos.
El cifrado es retrocompatible: las filas escritas antes de que se lanzara la funcionalidad se pueden leer como texto plano; las nuevas escrituras llevan un prefijo ENC: y siempre están cifradas.