Deploy
Synsema viene como un único binario estático — sin runtime en el destino. El bloque serve queda dev-clean en el repo; los knobs de deploy son flags del CLI, así el mismo archivo corre local y en prod sin ediciones.
synsema serve app.syn # dev: :8080, HTTP plano, sin setup
synsema serve app.syn --port 443 --domain example.com,www.example.com --tls-auto admin@example.com # prod: HTTPS
Flags de serve
| Flag | Efecto |
|---|---|
--port N | Override de serve on N y concede serve(N). |
--domain d1,d2 | Dominios ACME (SAN). |
--tls-auto <email> | HTTPS automático (ACME) — es el switch dev↔prod; necesita un dominio. |
--tls-cert / --tls-key | TLS manual (mutuamente excluyente con --tls-auto). |
--bind <addr> | Dirección de bind (default 0.0.0.0). |
Precedencia: flag del CLI > cláusula del archivo > default. Sin --tls-auto → HTTP plano (dev); con --tls-auto → TLS (prod).
Config por entorno (mantené el repo dev-clean)
El archivo .syn no cambia entre tu laptop y el server, así que git pull en prod nunca genera conflictos. Todo lo que difiere vive fuera del código.
Knobs del server → flags del CLI. --port, --domain, --tls-auto (tabla de arriba). El flag gana sobre la cláusula del archivo.
Valores de la app → el entorno. Todo lo que leas con env("NAME", default) — p. ej. la URL pública canónica que alimenta tus tags canonical/OG/sitemap:
require env("SITE_URL")
let SITE be env("SITE_URL", "http://127.0.0.1:8080") -- default dev; prod lo pisa
Seteala en prod desde el entorno (Environment=SITE_URL=https://example.com en systemd, -e SITE_URL=… en Docker). La resolución es process env > .env > default del código, así que no hace falta editar el repo.
¿Dos apps en un mismo host? Dale a cada una su puerto — el código queda idéntico: synsema serve api.syn --port 8081 y synsema serve admin.syn --port 8082. Como --port pisa serve on N y concede serve(N), no cambia nada en ninguno de los dos archivos.
HTTPS, paso a paso (certificado gratis y auto-renovable)
--tls-auto obtiene un certificado gratis de Let's Encrypt (ACME) y lo auto-renueva — sin certbot, sin cron. Qué necesitás:
1. Un dominio apuntando a la IP del server (un registro DNS A/AAAA).
2. Puertos 80 y 443 alcanzables — el 80 responde el desafío ACME una vez, después redirige al 443.
3. Correr con el dominio + un email de contacto:
synsema serve app.syn --port 443 --domain example.com,www.example.com --tls-auto you@example.com
Al primer arranque Synsema obtiene el certificado, sirve HTTPS en 443, redirige HTTP→HTTPS, y auto-renueva ~30 días antes del vencimiento (90 días). Los certificados se guardan (SYNSEMA_CERT_DIR → ~/.synsema/certs), así que un restart los recarga (sin re-emisión → sin rate-limit).
¿Ya tenés un certificado? Usá --tls-cert cert.pem --tls-key key.pem (mutuamente excluyente con --tls-auto). Bajo systemd, dale al servicio un HOME/StateDirectory escribible (abajo) para que pueda guardar los certificados.
synsema daemon vs systemd — elegí uno
synsema daemon start app.syn— manager de background integrado (status/logs/stop/restart). Sin config de SO, pero sin arranque al boot ni restart al crashear. Bueno para dev / máquinas sin systemd.- systemd — supervisor del SO: arranque al boot (
enable),Restart=always, logs en journald. Usalo para producción.
[Service]
ExecStart=/usr/local/bin/synsema serve /opt/app/app.syn --port 443 --domain example.com --tls-auto admin@example.com
Restart=always
StateDirectory=synsema # HOME escribible para el fallback ~/.synsema/certs
Varios sitios en un mismo host (Synsema es su propio edge proxy)
Dos procesos no pueden bindear ambos :443, y no necesitás nginx/Caddy. Un proceso Synsema es el edge: termina TLS para cada dominio (un cert SAN) y enruta por Host a cada backend, que corre en HTTP plano en un puerto privado.
-- edge.syn — TLS + routing por Host para cada sitio del server
require serve(443)
require net("127.0.0.1") -- deny-by-default: el edge sólo habla con localhost
serve on 443
host "example.com"
route "GET /" -- raíz: /*path NO matchea "/"
proxy to "http://127.0.0.1:8080"
route "GET /*path"
proxy to "http://127.0.0.1:8080"
route "POST /*path"
proxy to "http://127.0.0.1:8080"
host "docs.example.com"
route "GET /"
proxy to "http://127.0.0.1:8791"
route "GET /*path"
proxy to "http://127.0.0.1:8791"
route "POST /*path"
proxy to "http://127.0.0.1:8791"
Corré el edge con un cert SAN para todos los dominios; cada backend en HTTP plano, sólo localhost, con su propio repo/versión/servicio:
synsema serve edge.syn --port 443 --domain example.com,docs.example.com --tls-auto admin@example.com
synsema serve app.syn --port 8080 --bind 127.0.0.1
synsema serve docs.syn --port 8791 --bind 127.0.0.1
- Gotcha de la raíz:
route "GET /*path"exige ≥1 segmento — no matchea/. Agregároute "GET /"también (por método) para que la home llegue al backend. - Por método:
routeliga método+path — declará cada método que reenvíes (GET, POST, …). proxy toreenvía status + content-type + body y los headers end-to-end del upstream (Location,Set-Cookie,Cache-Control,ETag, …), así redirects, cookies y caching funcionan a través del edge; los hop-by-hop se descartan.- Deploys independientes: reiniciás un backend sin tocar los otros; cada uno puede correr su propia versión de Synsema detrás del mismo edge.
Docker y Kubernetes
docker run -d --restart unless-stopped -e ANTHROPIC_API_KEY=sk-... synsema serve app.syn
En K8s, command: ["synsema", "serve", "/app/agent.syn"] e inyectá claves vía secretKeyRef. Los secretos/config vienen del environment en prod (override de .env) — ver Secretos.
Actualizar
Un server corriendo no se auto-actualiza. synsema update reemplaza el binario en disco; systemctl restart lo aplica. Los certs TLS persisten (guardados + auto-renovados), así que un restart los recarga — sin pegarle al rate-limit de Let's Encrypt.