[{"data":1,"prerenderedAt":968},["ShallowReactive",2],{"doc-es-\u002Fes\u002Fdocs\u002Fred\u002Fingress-tls":3,"docs-es-all":899},{"id":4,"title":5,"body":6,"category":880,"description":881,"draft":882,"extension":883,"icon":884,"lastReviewed":885,"meta":886,"navigation":459,"order":35,"path":887,"prerequisites":888,"readingTime":890,"seo":891,"stem":892,"tags":893,"__hash__":898},"docs_es\u002Fes\u002Fdocs\u002Fred\u002Fingress-tls.md","Ingress y TLS automático",{"type":7,"value":8,"toc":862},"minimark",[9,13,16,21,91,94,111,117,121,124,129,136,146,150,157,206,209,212,240,244,251,254,329,336,340,351,394,405,409,412,500,518,522,525,618,622,625,689,692,696,700,703,769,772,794,798,801,821,827,831,834,838,858],[10,11,12],"p",{},"HeroCtl trae un router integrado embebido en el plano de control. No lo instalas, no lo configuras, no lo actualizas. Al levantar el cluster, el router ya está activo en los puertos 80 y 443 de cada nodo servidor.",[10,14,15],{},"Eso significa que exponer una aplicación en internet es una línea en el spec del job.",[17,18,20],"h2",{"id":19},"el-camino-mas-corto","El camino más corto",[22,23,28],"pre",{"className":24,"code":25,"language":26,"meta":27,"style":27},"language-yaml shiki shiki-themes github-dark-default","job: minha-api\ningress:\n  host: api.exemplo.com\n  port: http\n  tls: true\n","yaml","",[29,30,31,48,57,68,79],"code",{"__ignoreMap":27},[32,33,36,40,44],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sPWt5","job",[32,41,43],{"class":42},"sZEs4",": ",[32,45,47],{"class":46},"s9uIt","minha-api\n",[32,49,51,54],{"class":34,"line":50},2,[32,52,53],{"class":38},"ingress",[32,55,56],{"class":42},":\n",[32,58,60,63,65],{"class":34,"line":59},3,[32,61,62],{"class":38},"  host",[32,64,43],{"class":42},[32,66,67],{"class":46},"api.exemplo.com\n",[32,69,71,74,76],{"class":34,"line":70},4,[32,72,73],{"class":38},"  port",[32,75,43],{"class":42},[32,77,78],{"class":46},"http\n",[32,80,82,85,87],{"class":34,"line":81},5,[32,83,84],{"class":38},"  tls",[32,86,43],{"class":42},[32,88,90],{"class":89},"sFSAA","true\n",[10,92,93],{},"Con eso el cluster hace tres cosas en secuencia:",[95,96,97,105,108],"ol",{},[98,99,100,101,104],"li",{},"Resuelve el host ",[29,102,103],{},"api.exemplo.com"," a cualquier alocación saludable del job.",[98,106,107],{},"Solicita un certificado válido para ese dominio en la primera request.",[98,109,110],{},"Renueva ese certificado antes del vencimiento, sin intervención.",[10,112,113,114,116],{},"Solo necesitas apuntar el DNS de ",[29,115,103],{}," a las IPs de los nodos servidores. El resto corre solo.",[17,118,120],{"id":119},"como-se-emite-el-certificado","Cómo se emite el certificado",[10,122,123],{},"HeroCtl usa Let's Encrypt como autoridad certificadora por defecto. Detrás de eso hay dos mecanismos de validación soportados.",[125,126,128],"h3",{"id":127},"http-01-default","HTTP-01 (default)",[10,130,131,132,135],{},"Funciona para cualquier dominio público que apunta al cluster. Cuando una autoridad pide prueba de posesión, el router integrado responde en la ruta ",[29,133,134],{},"\u002F.well-known\u002Facme-challenge\u002F"," automáticamente. Nada necesita ser configurado.",[137,138,139],"blockquote",{},[10,140,141,145],{},[142,143,144],"strong",{},"Atención:"," HTTP-01 exige que el puerto 80 esté accesible externamente. Si el firewall bloquea el 80, la emisión falla.",[125,147,149],{"id":148},"dns-01-para-wildcards","DNS-01 (para wildcards)",[10,151,152,153,156],{},"Si necesitas un certificado wildcard (",[29,154,155],{},"*.exemplo.com","), usa DNS-01. Configura el proveedor DNS en el spec del cluster:",[22,158,160],{"className":24,"code":159,"language":26,"meta":27,"style":27},"acme:\n  challenge: dns-01\n  provider: cloudflare\n  credentials:\n    api_token: ${secret.cloudflare_token}\n",[29,161,162,169,179,189,196],{"__ignoreMap":27},[32,163,164,167],{"class":34,"line":35},[32,165,166],{"class":38},"acme",[32,168,56],{"class":42},[32,170,171,174,176],{"class":34,"line":50},[32,172,173],{"class":38},"  challenge",[32,175,43],{"class":42},[32,177,178],{"class":46},"dns-01\n",[32,180,181,184,186],{"class":34,"line":59},[32,182,183],{"class":38},"  provider",[32,185,43],{"class":42},[32,187,188],{"class":46},"cloudflare\n",[32,190,191,194],{"class":34,"line":70},[32,192,193],{"class":38},"  credentials",[32,195,56],{"class":42},[32,197,198,201,203],{"class":34,"line":81},[32,199,200],{"class":38},"    api_token",[32,202,43],{"class":42},[32,204,205],{"class":46},"${secret.cloudflare_token}\n",[10,207,208],{},"Proveedores soportados nativamente: Cloudflare, Route53, DigitalOcean, Hostinger, Hetzner. Otros van por plugin externo.",[10,210,211],{},"Con DNS-01 activo, basta declarar:",[22,213,215],{"className":24,"code":214,"language":26,"meta":27,"style":27},"ingress:\n  host: \"*.exemplo.com\"\n  tls: true\n",[29,216,217,223,232],{"__ignoreMap":27},[32,218,219,221],{"class":34,"line":35},[32,220,53],{"class":38},[32,222,56],{"class":42},[32,224,225,227,229],{"class":34,"line":50},[32,226,62],{"class":38},[32,228,43],{"class":42},[32,230,231],{"class":46},"\"*.exemplo.com\"\n",[32,233,234,236,238],{"class":34,"line":59},[32,235,84],{"class":38},[32,237,43],{"class":42},[32,239,90],{"class":89},[17,241,243],{"id":242},"redireccion-http-https","Redirección HTTP → HTTPS",[10,245,246,247,250],{},"Cuando ",[29,248,249],{},"tls: true",", todo tráfico que llega al puerto 80 es redirigido con 301 al 443. No necesitas duplicar configuración.",[10,252,253],{},"Para forzar HSTS:",[22,255,257],{"className":24,"code":256,"language":26,"meta":27,"style":27},"ingress:\n  host: api.exemplo.com\n  tls: true\n  hsts:\n    enabled: true\n    max_age: 31536000\n    include_subdomains: true\n    preload: false\n",[29,258,259,265,273,281,288,297,308,318],{"__ignoreMap":27},[32,260,261,263],{"class":34,"line":35},[32,262,53],{"class":38},[32,264,56],{"class":42},[32,266,267,269,271],{"class":34,"line":50},[32,268,62],{"class":38},[32,270,43],{"class":42},[32,272,67],{"class":46},[32,274,275,277,279],{"class":34,"line":59},[32,276,84],{"class":38},[32,278,43],{"class":42},[32,280,90],{"class":89},[32,282,283,286],{"class":34,"line":70},[32,284,285],{"class":38},"  hsts",[32,287,56],{"class":42},[32,289,290,293,295],{"class":34,"line":81},[32,291,292],{"class":38},"    enabled",[32,294,43],{"class":42},[32,296,90],{"class":89},[32,298,300,303,305],{"class":34,"line":299},6,[32,301,302],{"class":38},"    max_age",[32,304,43],{"class":42},[32,306,307],{"class":89},"31536000\n",[32,309,311,314,316],{"class":34,"line":310},7,[32,312,313],{"class":38},"    include_subdomains",[32,315,43],{"class":42},[32,317,90],{"class":89},[32,319,321,324,326],{"class":34,"line":320},8,[32,322,323],{"class":38},"    preload",[32,325,43],{"class":42},[32,327,328],{"class":89},"false\n",[10,330,331,332,335],{},"No habilites ",[29,333,334],{},"preload"," sin entender el compromiso. Es difícil revertir.",[17,337,339],{"id":338},"multiples-dominios-para-la-misma-app","Múltiples dominios para la misma app",[10,341,342,343,346,347,350],{},"Patrón común: ",[29,344,345],{},"www.exemplo.com"," y ",[29,348,349],{},"exemplo.com"," apuntando a la misma aplicación, con uno siendo canónico.",[22,352,354],{"className":24,"code":353,"language":26,"meta":27,"style":27},"ingress:\n  host: exemplo.com\n  redirect_from:\n    - www.exemplo.com\n  tls: true\n",[29,355,356,362,371,378,386],{"__ignoreMap":27},[32,357,358,360],{"class":34,"line":35},[32,359,53],{"class":38},[32,361,56],{"class":42},[32,363,364,366,368],{"class":34,"line":50},[32,365,62],{"class":38},[32,367,43],{"class":42},[32,369,370],{"class":46},"exemplo.com\n",[32,372,373,376],{"class":34,"line":59},[32,374,375],{"class":38},"  redirect_from",[32,377,56],{"class":42},[32,379,380,383],{"class":34,"line":70},[32,381,382],{"class":42},"    - ",[32,384,385],{"class":46},"www.exemplo.com\n",[32,387,388,390,392],{"class":34,"line":81},[32,389,84],{"class":38},[32,391,43],{"class":42},[32,393,90],{"class":89},[10,395,396,397,400,401,404],{},"Cada dominio en ",[29,398,399],{},"redirect_from"," recibe su propio certificado y responde 301 al ",[29,402,403],{},"host"," canónico.",[17,406,408],{"id":407},"ruteo-por-path","Ruteo por path",[10,410,411],{},"Mismo host, aplicaciones diferentes en paths diferentes:",[22,413,415],{"className":24,"code":414,"language":26,"meta":27,"style":27},"# job: site-marketing\ningress:\n  host: exemplo.com\n  path: \u002F\n  tls: true\n\n# job: api-publica\ningress:\n  host: exemplo.com\n  path: \u002Fapi\n  tls: true\n",[29,416,417,423,429,437,447,455,461,466,472,481,491],{"__ignoreMap":27},[32,418,419],{"class":34,"line":35},[32,420,422],{"class":421},"sH3jZ","# job: site-marketing\n",[32,424,425,427],{"class":34,"line":50},[32,426,53],{"class":38},[32,428,56],{"class":42},[32,430,431,433,435],{"class":34,"line":59},[32,432,62],{"class":38},[32,434,43],{"class":42},[32,436,370],{"class":46},[32,438,439,442,444],{"class":34,"line":70},[32,440,441],{"class":38},"  path",[32,443,43],{"class":42},[32,445,446],{"class":46},"\u002F\n",[32,448,449,451,453],{"class":34,"line":81},[32,450,84],{"class":38},[32,452,43],{"class":42},[32,454,90],{"class":89},[32,456,457],{"class":34,"line":299},[32,458,460],{"emptyLinePlaceholder":459},true,"\n",[32,462,463],{"class":34,"line":310},[32,464,465],{"class":421},"# job: api-publica\n",[32,467,468,470],{"class":34,"line":320},[32,469,53],{"class":38},[32,471,56],{"class":42},[32,473,475,477,479],{"class":34,"line":474},9,[32,476,62],{"class":38},[32,478,43],{"class":42},[32,480,370],{"class":46},[32,482,484,486,488],{"class":34,"line":483},10,[32,485,441],{"class":38},[32,487,43],{"class":42},[32,489,490],{"class":46},"\u002Fapi\n",[32,492,494,496,498],{"class":34,"line":493},11,[32,495,84],{"class":38},[32,497,43],{"class":42},[32,499,90],{"class":89},[10,501,502,503,506,507,510,511,506,514,517],{},"El router resuelve la precedencia por especificidad. ",[29,504,505],{},"\u002Fapi\u002Fusers"," cae en ",[29,508,509],{},"api-publica",". ",[29,512,513],{},"\u002Fsobre",[29,515,516],{},"site-marketing",".",[17,519,521],{"id":520},"cabeceras-customizadas","Cabeceras customizadas",[10,523,524],{},"Para agregar o remover headers en la respuesta:",[22,526,528],{"className":24,"code":527,"language":26,"meta":27,"style":27},"ingress:\n  host: api.exemplo.com\n  tls: true\n  headers:\n    add:\n      X-Frame-Options: DENY\n      X-Content-Type-Options: nosniff\n      Referrer-Policy: strict-origin\n    remove:\n      - Server\n      - X-Powered-By\n",[29,529,530,536,544,552,559,566,576,586,596,603,611],{"__ignoreMap":27},[32,531,532,534],{"class":34,"line":35},[32,533,53],{"class":38},[32,535,56],{"class":42},[32,537,538,540,542],{"class":34,"line":50},[32,539,62],{"class":38},[32,541,43],{"class":42},[32,543,67],{"class":46},[32,545,546,548,550],{"class":34,"line":59},[32,547,84],{"class":38},[32,549,43],{"class":42},[32,551,90],{"class":89},[32,553,554,557],{"class":34,"line":70},[32,555,556],{"class":38},"  headers",[32,558,56],{"class":42},[32,560,561,564],{"class":34,"line":81},[32,562,563],{"class":38},"    add",[32,565,56],{"class":42},[32,567,568,571,573],{"class":34,"line":299},[32,569,570],{"class":38},"      X-Frame-Options",[32,572,43],{"class":42},[32,574,575],{"class":46},"DENY\n",[32,577,578,581,583],{"class":34,"line":310},[32,579,580],{"class":38},"      X-Content-Type-Options",[32,582,43],{"class":42},[32,584,585],{"class":46},"nosniff\n",[32,587,588,591,593],{"class":34,"line":320},[32,589,590],{"class":38},"      Referrer-Policy",[32,592,43],{"class":42},[32,594,595],{"class":46},"strict-origin\n",[32,597,598,601],{"class":34,"line":474},[32,599,600],{"class":38},"    remove",[32,602,56],{"class":42},[32,604,605,608],{"class":34,"line":483},[32,606,607],{"class":42},"      - ",[32,609,610],{"class":46},"Server\n",[32,612,613,615],{"class":34,"line":493},[32,614,607],{"class":42},[32,616,617],{"class":46},"X-Powered-By\n",[17,619,621],{"id":620},"rate-limiting-basico","Rate limiting básico",[10,623,624],{},"Defensa en primera línea contra abuso:",[22,626,628],{"className":24,"code":627,"language":26,"meta":27,"style":27},"ingress:\n  host: api.exemplo.com\n  tls: true\n  rate_limit:\n    requests_per_second: 100\n    burst: 200\n    by: ip\n",[29,629,630,636,644,652,659,669,679],{"__ignoreMap":27},[32,631,632,634],{"class":34,"line":35},[32,633,53],{"class":38},[32,635,56],{"class":42},[32,637,638,640,642],{"class":34,"line":50},[32,639,62],{"class":38},[32,641,43],{"class":42},[32,643,67],{"class":46},[32,645,646,648,650],{"class":34,"line":59},[32,647,84],{"class":38},[32,649,43],{"class":42},[32,651,90],{"class":89},[32,653,654,657],{"class":34,"line":70},[32,655,656],{"class":38},"  rate_limit",[32,658,56],{"class":42},[32,660,661,664,666],{"class":34,"line":81},[32,662,663],{"class":38},"    requests_per_second",[32,665,43],{"class":42},[32,667,668],{"class":89},"100\n",[32,670,671,674,676],{"class":34,"line":299},[32,672,673],{"class":38},"    burst",[32,675,43],{"class":42},[32,677,678],{"class":89},"200\n",[32,680,681,684,686],{"class":34,"line":310},[32,682,683],{"class":38},"    by",[32,685,43],{"class":42},[32,687,688],{"class":46},"ip\n",[10,690,691],{},"Límites más elaborados (por token, por endpoint, con bypass para partners) quedan en la aplicación.",[17,693,695],{"id":694},"troubleshooting","Troubleshooting",[125,697,699],{"id":698},"el-certificado-no-fue-emitido","El certificado no fue emitido",[10,701,702],{},"Chequea tres cosas, en orden:",[704,705,706,722],"table",{},[707,708,709],"thead",{},[710,711,712,716,719],"tr",{},[713,714,715],"th",{},"Síntoma",[713,717,718],{},"Causa probable",[713,720,721],{},"Qué hacer",[723,724,725,740,756],"tbody",{},[710,726,727,734,737],{},[728,729,730,733],"td",{},[29,731,732],{},"dial tcp: timeout"," en el log del challenge",[728,735,736],{},"Puerto 80 cerrado",[728,738,739],{},"Liberar 80\u002Ftcp inbound en los nodos servidores",[710,741,742,747,750],{},[728,743,744],{},[29,745,746],{},"unauthorized: Invalid response",[728,748,749],{},"DNS apunta a otro lugar",[728,751,752,755],{},[29,753,754],{},"dig +short api.exemplo.com"," debe retornar IP de nodo servidor",[710,757,758,763,766],{},[728,759,760],{},[29,761,762],{},"too many failed authorizations",[728,764,765],{},"Pegaste el rate limit de Let's Encrypt",[728,767,768],{},"Aguardar 1h y revisar la config antes de intentar de nuevo",[10,770,771],{},"Inspecciona el estado de la emisión:",[22,773,777],{"className":774,"code":775,"language":776,"meta":27,"style":27},"language-bash shiki shiki-themes github-dark-default","heroctl ingress cert-status api.exemplo.com\n","bash",[29,778,779],{"__ignoreMap":27},[32,780,781,785,788,791],{"class":34,"line":35},[32,782,784],{"class":783},"sQhOw","heroctl",[32,786,787],{"class":46}," ingress",[32,789,790],{"class":46}," cert-status",[32,792,793],{"class":46}," api.exemplo.com\n",[125,795,797],{"id":796},"el-certificado-vencio-sin-renovar","El certificado venció sin renovar",[10,799,800],{},"La renovación corre 30 días antes del vencimiento. Si pasó de eso, hay error acumulado:",[22,802,804],{"className":774,"code":803,"language":776,"meta":27,"style":27},"heroctl ingress cert-renew api.exemplo.com --force\n",[29,805,806],{"__ignoreMap":27},[32,807,808,810,812,815,818],{"class":34,"line":35},[32,809,784],{"class":783},[32,811,787],{"class":46},[32,813,814],{"class":46}," cert-renew",[32,816,817],{"class":46}," api.exemplo.com",[32,819,820],{"class":89}," --force\n",[10,822,823,824,826],{},"Verifica también si ",[29,825,399],{}," aún apunta al cluster. Un dominio que fue movido a otro proveedor sin ser removido del spec rompe la renovación silenciosamente.",[125,828,830],{"id":829},"acme-challenge-intermitente","ACME challenge intermitente",[10,832,833],{},"Síntoma: a veces emite, a veces falla. Generalmente es DNS round-robin con una IP que no responde en 80, o un Cloudflare al frente en modo proxy. Para HTTP-01, el dominio debe resolver directo al cluster durante el desafío. Usa DNS-01 si mantienes Cloudflare proxy activado.",[17,835,837],{"id":836},"proximos-pasos","Próximos pasos",[839,840,841,850],"ul",{},[98,842,843,844,849],{},"Configurar ",[845,846,848],"a",{"href":847},"\u002Fes\u002Fdocs\u002Fred\u002Ffirewall","firewall"," para liberar solo lo necesario.",[98,851,852,853,857],{},"Entender el modelo de ",[845,854,856],{"href":855},"\u002Fes\u002Fdocs\u002Fseguridad\u002Fsecretos","secretos"," antes de inyectar tokens DNS en el spec.",[859,860,861],"style",{},"html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}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 .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}",{"title":27,"searchDepth":50,"depth":50,"links":863},[864,865,869,870,871,872,873,874,879],{"id":19,"depth":50,"text":20},{"id":119,"depth":50,"text":120,"children":866},[867,868],{"id":127,"depth":59,"text":128},{"id":148,"depth":59,"text":149},{"id":242,"depth":50,"text":243},{"id":338,"depth":50,"text":339},{"id":407,"depth":50,"text":408},{"id":520,"depth":50,"text":521},{"id":620,"depth":50,"text":621},{"id":694,"depth":50,"text":695,"children":875},[876,877,878],{"id":698,"depth":59,"text":699},{"id":796,"depth":59,"text":797},{"id":829,"depth":59,"text":830},{"id":836,"depth":50,"text":837},"rede","Cómo exponer aplicaciones por el puerto 443 con certificados emitidos y renovados automáticamente, sin operar un router externo.",false,"md","i-lucide-globe","2026-04-26",{},"\u002Fes\u002Fdocs\u002Fred\u002Fingress-tls",[889],"primeiro-deploy","7 min",{"title":5,"description":881},"es\u002Fdocs\u002Fred\u002Fingress-tls",[53,894,895,166,896,897],"tls","https","lets-encrypt","red","WcymopFLP0inxCKHakdgHq1uppwpvjIDBMCeusjT9hI",[900,906,912,917,923,928,934,938,943,948,952,953,959,963],{"path":901,"title":902,"description":903,"category":904,"order":35,"icon":905},"\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.","api","i-lucide-code",{"path":907,"title":908,"description":909,"category":910,"order":35,"icon":911},"\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":913,"title":914,"description":915,"category":910,"order":50,"icon":916},"\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":918,"title":919,"description":920,"category":921,"order":50,"icon":922},"\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":924,"title":925,"description":926,"category":921,"order":35,"icon":927},"\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":929,"title":930,"description":931,"category":932,"order":35,"icon":933},"\u002Fes\u002Fdocs\u002Foperaciones\u002Finstalacion","Instalación","Instala HeroCtl en cualquier servidor Linux con Docker en un solo comando. Cubre prerrequisitos, bootstrap y verificación.","operacoes","i-lucide-download",{"path":935,"title":936,"description":937,"category":932,"order":70,"icon":884},"\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.",{"path":939,"title":940,"description":941,"category":932,"order":50,"icon":942},"\u002Fes\u002Fdocs\u002Foperaciones\u002Fprimer-cluster","Levantar cluster de 3 nodos","Forma un cluster con 3 servidores en menos de 10 minutos. Tolera falla de 1 nodo sin indisponibilidad.","i-lucide-network",{"path":944,"title":945,"description":946,"category":932,"order":59,"icon":947},"\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":847,"title":949,"description":950,"category":880,"order":50,"icon":951},"Configuración de firewall","Qué puertos usa HeroCtl, cuáles necesitan estar abiertos y cuáles nunca deberían exponerse a internet.","i-lucide-shield",{"path":887,"title":5,"description":881,"category":880,"order":35,"icon":884},{"path":954,"title":955,"description":956,"category":957,"order":50,"icon":958},"\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":855,"title":960,"description":961,"category":957,"order":35,"icon":962},"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":964,"title":965,"description":966,"category":694,"order":35,"icon":967},"\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.","i-lucide-alert-triangle",1777362182790]