[{"data":1,"prerenderedAt":780},["ShallowReactive",2],{"doc-es-\u002Fes\u002Fdocs\u002Foperaciones\u002Finstalacion":3,"docs-es-all":711},{"id":4,"title":5,"body":6,"category":694,"description":695,"draft":696,"extension":697,"icon":698,"lastReviewed":699,"meta":700,"navigation":241,"order":145,"path":701,"prerequisites":702,"readingTime":703,"seo":704,"stem":705,"tags":706,"__hash__":710},"docs_es\u002Fes\u002Fdocs\u002Foperaciones\u002Finstalacion.md","Instalación",{"type":7,"value":8,"toc":680},"minimark",[9,13,18,21,110,125,129,132,165,168,207,210,214,217,275,289,323,327,330,386,389,393,396,420,431,434,468,476,480,485,491,529,535,539,556,560,563,567,581,585,588,659,670,676],[10,11,12],"p",{},"HeroCtl corre en cualquier servidor Linux con Docker. El binario es único y contiene los tres modos de ejecución: servidor, agente y CLI. Decides el rol de la máquina vía flag, no vía paquete.",[14,15,17],"h2",{"id":16},"prerrequisitos","Prerrequisitos",[10,19,20],{},"Antes de instalar, confirma el entorno. La lista es corta y firme.",[22,23,24,40],"table",{},[25,26,27],"thead",{},[28,29,30,34,37],"tr",{},[31,32,33],"th",{},"Requisito",[31,35,36],{},"Mínimo",[31,38,39],{},"Recomendado",[41,42,43,55,66,77,88,99],"tbody",{},[28,44,45,49,52],{},[46,47,48],"td",{},"Sistema",[46,50,51],{},"Linux x86_64 (kernel 5.4+)",[46,53,54],{},"Ubuntu 22.04 o Debian 12",[28,56,57,60,63],{},[46,58,59],{},"CPU",[46,61,62],{},"2 vCPU",[46,64,65],{},"4 vCPU",[28,67,68,71,74],{},[46,69,70],{},"RAM",[46,72,73],{},"2 GB",[46,75,76],{},"4 GB",[28,78,79,82,85],{},[46,80,81],{},"Disco",[46,83,84],{},"20 GB SSD",[46,86,87],{},"40 GB SSD",[28,89,90,93,96],{},[46,91,92],{},"Docker",[46,94,95],{},"20.10+",[46,97,98],{},"24+",[28,100,101,104,107],{},[46,102,103],{},"Puertos",[46,105,106],{},"8080, 8081, 8082 abiertos entre nodos",[46,108,109],{},"mismo",[111,112,113],"blockquote",{},[10,114,115,119,120,124],{},[116,117,118],"strong",{},"Nota:"," Docker debe estar en ejecución antes del install. Verifica con ",[121,122,123],"code",{},"docker info",". Si la salida da error de socket, ajusta permisos antes de continuar.",[14,126,128],{"id":127},"comando-de-instalacion","Comando de instalación",[10,130,131],{},"Un comando entrega el binario, configura el servicio y genera el archivo de configuración por defecto.",[133,134,139],"pre",{"className":135,"code":136,"language":137,"meta":138,"style":138},"language-bash shiki shiki-themes github-dark-default","curl -sSL https:\u002F\u002Fget.heroctl.com\u002Finstall.sh | sh\n","bash","",[121,140,141],{"__ignoreMap":138},[142,143,146,150,154,158,162],"span",{"class":144,"line":145},"line",1,[142,147,149],{"class":148},"sQhOw","curl",[142,151,153],{"class":152},"sFSAA"," -sSL",[142,155,157],{"class":156},"s9uIt"," https:\u002F\u002Fget.heroctl.com\u002Finstall.sh",[142,159,161],{"class":160},"suJrU"," |",[142,163,164],{"class":148}," sh\n",[10,166,167],{},"El script ejecuta cuatro pasos, en orden:",[169,170,171,179,193,200],"ol",{},[172,173,174,175,178],"li",{},"Descarga el binario más reciente a ",[121,176,177],{},"\u002Fusr\u002Flocal\u002Fbin\u002Fheroctl",".",[172,180,181,182,185,186,189,190,178],{},"Crea el usuario de sistema ",[121,183,184],{},"heroctl"," y los directorios ",[121,187,188],{},"\u002Fetc\u002Fheroctl\u002F"," y ",[121,191,192],{},"\u002Fvar\u002Flib\u002Fheroctl\u002F",[172,194,195,196,199],{},"Registra un servicio systemd (",[121,197,198],{},"heroctl.service",") sin habilitar el arranque automático.",[172,201,202,203,206],{},"Genera ",[121,204,205],{},"\u002Fetc\u002Fheroctl\u002Fserver.yaml"," con defaults seguros (bind en 127.0.0.1, sin TLS).",[10,208,209],{},"Sin sorpresas. El script no toca nada fuera de esas rutas y no inicia procesos.",[14,211,213],{"id":212},"verificacion-post-instalacion","Verificación post-instalación",[10,215,216],{},"Tras terminar el script, dos comandos confirman que el binario responde.",[133,218,220],{"className":135,"code":219,"language":137,"meta":138,"style":138},"heroctl version\n# heroctl 1.0.0 (commit abc123, build 2026-04-20)\n\nheroctl status\n# binary: ok\n# config: \u002Fetc\u002Fheroctl\u002Fserver.yaml\n# docker: connected (24.0.7)\n# service: inactive (não iniciado)\n",[121,221,222,229,236,243,251,257,263,269],{"__ignoreMap":138},[142,223,224,226],{"class":144,"line":145},[142,225,184],{"class":148},[142,227,228],{"class":156}," version\n",[142,230,232],{"class":144,"line":231},2,[142,233,235],{"class":234},"sH3jZ","# heroctl 1.0.0 (commit abc123, build 2026-04-20)\n",[142,237,239],{"class":144,"line":238},3,[142,240,242],{"emptyLinePlaceholder":241},true,"\n",[142,244,246,248],{"class":144,"line":245},4,[142,247,184],{"class":148},[142,249,250],{"class":156}," status\n",[142,252,254],{"class":144,"line":253},5,[142,255,256],{"class":234},"# binary: ok\n",[142,258,260],{"class":144,"line":259},6,[142,261,262],{"class":234},"# config: \u002Fetc\u002Fheroctl\u002Fserver.yaml\n",[142,264,266],{"class":144,"line":265},7,[142,267,268],{"class":234},"# docker: connected (24.0.7)\n",[142,270,272],{"class":144,"line":271},8,[142,273,274],{"class":234},"# service: inactive (não iniciado)\n",[10,276,277,278,281,282,284,285,288],{},"Si ",[121,279,280],{},"docker: connected"," aparece con error, el binario no logra hablar con el socket. Agrega el usuario ",[121,283,184],{}," al grupo ",[121,286,287],{},"docker"," y reinicia el servicio.",[133,290,292],{"className":135,"code":291,"language":137,"meta":138,"style":138},"sudo usermod -aG docker heroctl\nsudo systemctl restart heroctl\n",[121,293,294,311],{"__ignoreMap":138},[142,295,296,299,302,305,308],{"class":144,"line":145},[142,297,298],{"class":148},"sudo",[142,300,301],{"class":156}," usermod",[142,303,304],{"class":152}," -aG",[142,306,307],{"class":156}," docker",[142,309,310],{"class":156}," heroctl\n",[142,312,313,315,318,321],{"class":144,"line":231},[142,314,298],{"class":148},[142,316,317],{"class":156}," systemctl",[142,319,320],{"class":156}," restart",[142,322,310],{"class":156},[14,324,326],{"id":325},"los-tres-modos-del-binario","Los tres modos del binario",[10,328,329],{},"El mismo ejecutable cambia de rol por la flag inicial. No existe paquete separado.",[22,331,332,345],{},[25,333,334],{},[28,335,336,339,342],{},[31,337,338],{},"Modo",[31,340,341],{},"Comando",[31,343,344],{},"Para qué",[41,346,347,360,373],{},[28,348,349,352,357],{},[46,350,351],{},"Servidor",[46,353,354],{},[121,355,356],{},"heroctl server",[46,358,359],{},"Plano de control. Decide dónde corre todo.",[28,361,362,365,370],{},[46,363,364],{},"Agente",[46,366,367],{},[121,368,369],{},"heroctl agent",[46,371,372],{},"Worker. Ejecuta contenedores y reporta salud.",[28,374,375,378,383],{},[46,376,377],{},"CLI",[46,379,380],{},[121,381,382],{},"heroctl \u003Ccmd>",[46,384,385],{},"Cliente local. Habla con cualquier servidor vía API.",[10,387,388],{},"En producción, 3 nodos corren servidor + agente. Workers extras corren solo agente. El modo CLI es stateless y puede correr desde el laptop del operador.",[14,390,392],{"id":391},"bootstrap-inicial","Bootstrap inicial",[10,394,395],{},"El primer nodo necesita inicializar el estado del cluster. Ese paso es único y solo ocurre una vez en la vida de la instalación.",[133,397,399],{"className":135,"code":398,"language":137,"meta":138,"style":138},"sudo heroctl server --bootstrap --advertise 10.0.0.1\n",[121,400,401],{"__ignoreMap":138},[142,402,403,405,408,411,414,417],{"class":144,"line":145},[142,404,298],{"class":148},[142,406,407],{"class":156}," heroctl",[142,409,410],{"class":156}," server",[142,412,413],{"class":152}," --bootstrap",[142,415,416],{"class":152}," --advertise",[142,418,419],{"class":152}," 10.0.0.1\n",[10,421,422,423,426,427,430],{},"La flag ",[121,424,425],{},"--advertise"," es la IP que otros nodos usarán para conectar. En entorno de prueba, puede ser ",[121,428,429],{},"127.0.0.1",". En producción, es la IP privada de la máquina.",[10,432,433],{},"Tras el bootstrap, el servicio queda en ejecución en segundo plano. Confirma con:",[133,435,437],{"className":135,"code":436,"language":137,"meta":138,"style":138},"heroctl cluster status\n# nodes:    1\n# leader:   self\n# applied:  42\n# health:   ok\n",[121,438,439,448,453,458,463],{"__ignoreMap":138},[142,440,441,443,446],{"class":144,"line":145},[142,442,184],{"class":148},[142,444,445],{"class":156}," cluster",[142,447,250],{"class":156},[142,449,450],{"class":144,"line":231},[142,451,452],{"class":234},"# nodes:    1\n",[142,454,455],{"class":144,"line":238},[142,456,457],{"class":234},"# leader:   self\n",[142,459,460],{"class":144,"line":245},[142,461,462],{"class":234},"# applied:  42\n",[142,464,465],{"class":144,"line":253},[142,466,467],{"class":234},"# health:   ok\n",[10,469,470,471,178],{},"Para levantar nodos adicionales y formar un cluster real, sigue a ",[472,473,475],"a",{"href":474},"\u002Fes\u002Fdocs\u002Foperaciones\u002Fprimer-cluster","Levantar cluster de 3 nodos",[14,477,479],{"id":478},"problemas-comunes","Problemas comunes",[481,482,484],"h3",{"id":483},"puerto-8080-en-uso","Puerto 8080 en uso",[10,486,487,488,490],{},"HeroCtl reserva 8080 para la API HTTP. Si otro proceso ya lo ocupa, edita ",[121,489,205],{}," antes del bootstrap.",[133,492,496],{"className":493,"code":494,"language":495,"meta":138,"style":138},"language-yaml shiki shiki-themes github-dark-default","api:\n  bind: 0.0.0.0\n  port: 9080\n","yaml",[121,497,498,508,519],{"__ignoreMap":138},[142,499,500,504],{"class":144,"line":145},[142,501,503],{"class":502},"sPWt5","api",[142,505,507],{"class":506},"sZEs4",":\n",[142,509,510,513,516],{"class":144,"line":231},[142,511,512],{"class":502},"  bind",[142,514,515],{"class":506},": ",[142,517,518],{"class":152},"0.0.0.0\n",[142,520,521,524,526],{"class":144,"line":238},[142,522,523],{"class":502},"  port",[142,525,515],{"class":506},[142,527,528],{"class":152},"9080\n",[10,530,531,532,178],{},"Reinicia el servicio con ",[121,533,534],{},"sudo systemctl restart heroctl",[481,536,538],{"id":537},"permiso-denegado-en-docker","Permiso denegado en Docker",[10,540,541,542,545,546,548,549,551,552,555],{},"El mensaje ",[121,543,544],{},"permission denied while trying to connect to the Docker daemon"," aparece cuando el usuario ",[121,547,184],{}," no está en el grupo ",[121,550,287],{},". Resuelve con el ",[121,553,554],{},"usermod"," mostrado arriba y reinicia el servicio.",[481,557,559],{"id":558},"firewall-bloqueando-el-cluster","Firewall bloqueando el cluster",[10,561,562],{},"En proveedores como DigitalOcean o Hetzner, el firewall externo bloquea 8080–8082 por defecto. Libera los tres puertos entre las IPs de los nodos antes de intentar formar cluster. Para acceso externo a la API, mantén 8080 abierto solo para IPs administrativas.",[481,564,566],{"id":565},"binario-no-encontrado-tras-install","Binario no encontrado tras install",[10,568,569,570,573,574,577,578,178],{},"El script instala en ",[121,571,572],{},"\u002Fusr\u002Flocal\u002Fbin\u002F",". Si el ",[121,575,576],{},"PATH"," de la sesión actual no incluye ese directorio, abre un nuevo shell o ejecuta ",[121,579,580],{},"hash -r",[14,582,584],{"id":583},"desinstalacion","Desinstalación",[10,586,587],{},"Revertir es simétrico. Remueve servicio, binario y datos, en ese orden.",[133,589,591],{"className":135,"code":590,"language":137,"meta":138,"style":138},"sudo systemctl stop heroctl && sudo systemctl disable heroctl\nsudo rm \u002Fetc\u002Fsystemd\u002Fsystem\u002Fheroctl.service\nsudo rm \u002Fusr\u002Flocal\u002Fbin\u002Fheroctl\nsudo rm -rf \u002Fetc\u002Fheroctl \u002Fvar\u002Flib\u002Fheroctl\nsudo userdel heroctl\n",[121,592,593,616,626,635,650],{"__ignoreMap":138},[142,594,595,597,599,602,604,607,609,611,614],{"class":144,"line":145},[142,596,298],{"class":148},[142,598,317],{"class":156},[142,600,601],{"class":156}," stop",[142,603,407],{"class":156},[142,605,606],{"class":506}," && ",[142,608,298],{"class":148},[142,610,317],{"class":156},[142,612,613],{"class":156}," disable",[142,615,310],{"class":156},[142,617,618,620,623],{"class":144,"line":231},[142,619,298],{"class":148},[142,621,622],{"class":156}," rm",[142,624,625],{"class":156}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fheroctl.service\n",[142,627,628,630,632],{"class":144,"line":238},[142,629,298],{"class":148},[142,631,622],{"class":156},[142,633,634],{"class":156}," \u002Fusr\u002Flocal\u002Fbin\u002Fheroctl\n",[142,636,637,639,641,644,647],{"class":144,"line":245},[142,638,298],{"class":148},[142,640,622],{"class":156},[142,642,643],{"class":152}," -rf",[142,645,646],{"class":156}," \u002Fetc\u002Fheroctl",[142,648,649],{"class":156}," \u002Fvar\u002Flib\u002Fheroctl\n",[142,651,652,654,657],{"class":144,"line":253},[142,653,298],{"class":148},[142,655,656],{"class":156}," userdel",[142,658,310],{"class":156},[111,660,661],{},[10,662,663,666,667,669],{},[116,664,665],{},"Atención:"," el directorio ",[121,668,192],{}," contiene el estado del cluster. Borrarlo significa perder el historial de deploys y definiciones de jobs. Haz snapshot antes si hay chance de reinstalar.",[10,671,672,673,178],{},"Próximo paso: ",[472,674,675],{"href":474},"formar un cluster de 3 nodos",[677,678,679],"style",{},"html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}",{"title":138,"searchDepth":231,"depth":231,"links":681},[682,683,684,685,686,687,693],{"id":16,"depth":231,"text":17},{"id":127,"depth":231,"text":128},{"id":212,"depth":231,"text":213},{"id":325,"depth":231,"text":326},{"id":391,"depth":231,"text":392},{"id":478,"depth":231,"text":479,"children":688},[689,690,691,692],{"id":483,"depth":238,"text":484},{"id":537,"depth":238,"text":538},{"id":558,"depth":238,"text":559},{"id":565,"depth":238,"text":566},{"id":583,"depth":231,"text":584},"operacoes","Instala HeroCtl en cualquier servidor Linux con Docker en un solo comando. Cubre prerrequisitos, bootstrap y verificación.",false,"md","i-lucide-download","2026-04-26",{},"\u002Fes\u002Fdocs\u002Foperaciones\u002Finstalacion",[],"6 min",{"title":5,"description":695},"es\u002Fdocs\u002Foperaciones\u002Finstalacion",[707,708,709],"instalacion","primeros-pasos","linux","3Yc211f0YwMdRl4HYMLq1frmkyJQHkr9E9iC4MkJH7s",[712,717,723,728,734,739,740,745,748,753,759,763,769,774],{"path":713,"title":714,"description":715,"category":503,"order":145,"icon":716},"\u002Fes\u002Fdocs\u002Fapi\u002Freferencia-api","Referencia de la API REST","Endpoints, autenticación JWT, ejemplos con curl y patrones de error de la API de HeroCtl.","i-lucide-code",{"path":718,"title":719,"description":720,"category":721,"order":145,"icon":722},"\u002Fes\u002Fdocs\u002Fdeploy\u002Fprimer-deploy","Deploy de la primera app","Levanta una aplicación Node.js con base Postgres en 50 líneas de YAML. Incluye health check, rolling update y rollback.","deploy","i-lucide-rocket",{"path":724,"title":725,"description":726,"category":721,"order":231,"icon":727},"\u002Fes\u002Fdocs\u002Fdeploy\u002Frolling-canary-blue-green","Rolling, canary, blue-green y rainbow","Cuatro estrategias de deploy. Cuándo usar cada una, con ejemplos completos y trade-offs honestos.","i-lucide-git-branch",{"path":729,"title":730,"description":731,"category":732,"order":231,"icon":733},"\u002Fes\u002Fdocs\u002Fobservabilidad\u002Fbackup-restauracion","Backup y restauración del estado del cluster","Cómo guardar, programar y restaurar snapshots del plano de control de HeroCtl. Estrategia de disaster recovery.","observabilidade","i-lucide-archive",{"path":735,"title":736,"description":737,"category":732,"order":145,"icon":738},"\u002Fes\u002Fdocs\u002Fobservabilidad\u002Fmetricas-logs","Métricas y logs","Recolección de métricas, logs y traces sin montar una pila de observabilidad externa. Cuándo vale, y cuándo integrar con herramienta de fuera.","i-lucide-activity",{"path":701,"title":5,"description":695,"category":694,"order":145,"icon":698},{"path":741,"title":742,"description":743,"category":694,"order":245,"icon":744},"\u002Fes\u002Fdocs\u002Foperaciones\u002Fmulti-region","Multi-region (en planificación Q4 2026)","Qué esperar de multi-region en HeroCtl, cómo correr en varias regiones hoy y la hoja de ruta hasta 2027.","i-lucide-globe",{"path":474,"title":475,"description":746,"category":694,"order":231,"icon":747},"Forma un cluster con 3 servidores en menos de 10 minutos. Tolera falla de 1 nodo sin indisponibilidad.","i-lucide-network",{"path":749,"title":750,"description":751,"category":694,"order":238,"icon":752},"\u002Fes\u002Fdocs\u002Foperaciones\u002Freferencia-cli","Referencia completa del CLI","Todos los comandos heroctl con sinopsis, flags y ejemplo. Úsalo como chuleta de mesa.","i-lucide-terminal",{"path":754,"title":755,"description":756,"category":757,"order":231,"icon":758},"\u002Fes\u002Fdocs\u002Fred\u002Ffirewall","Configuración de firewall","Qué puertos usa HeroCtl, cuáles necesitan estar abiertos y cuáles nunca deberían exponerse a internet.","rede","i-lucide-shield",{"path":760,"title":761,"description":762,"category":757,"order":145,"icon":744},"\u002Fes\u002Fdocs\u002Fred\u002Fingress-tls","Ingress y TLS automático","Cómo exponer aplicaciones por el puerto 443 con certificados emitidos y renovados automáticamente, sin operar un router externo.",{"path":764,"title":765,"description":766,"category":767,"order":231,"icon":768},"\u002Fes\u002Fdocs\u002Fseguridad\u002Frbac","RBAC y control de acceso (Business+)","Modelo de roles, políticas y tokens para limitar quién puede enviar, leer y operar el cluster.","seguranca","i-lucide-users",{"path":770,"title":771,"description":772,"category":767,"order":145,"icon":773},"\u002Fes\u002Fdocs\u002Fseguridad\u002Fsecretos","Gestión de secretos","Cómo guardar contraseñas, tokens y claves fuera del spec del job, con cifrado en reposo y rotación versionada.","i-lucide-key",{"path":775,"title":776,"description":777,"category":778,"order":145,"icon":779},"\u002Fes\u002Fdocs\u002Ftroubleshooting\u002Fproblemas-comunes","Troubleshooting de problemas comunes","Los 12 problemas más frecuentes en clusters HeroCtl, con síntoma, diagnóstico y corrección paso a paso.","troubleshooting","i-lucide-alert-triangle",1777362182598]