[{"data":1,"prerenderedAt":967},["ShallowReactive",2],{"doc-en-\u002Fen\u002Fdocs\u002Fnetworking\u002Fingress-tls":3,"docs-en-all":898},{"id":4,"title":5,"body":6,"category":879,"description":880,"draft":881,"extension":882,"icon":883,"lastReviewed":884,"meta":885,"navigation":459,"order":35,"path":886,"prerequisites":887,"readingTime":889,"seo":890,"stem":891,"tags":892,"__hash__":897},"docs_en\u002Fen\u002Fdocs\u002Fnetworking\u002Fingress-tls.md","Ingress and automatic TLS",{"type":7,"value":8,"toc":861},"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,517,521,524,617,621,624,688,691,695,699,702,768,771,793,797,800,820,826,830,833,837,857],[10,11,12],"p",{},"HeroCtl ships with an integrated router embedded in the control plane. You do not install, configure, or update it. When the cluster comes up, the router is already active on ports 80 and 443 of every server node.",[10,14,15],{},"That means exposing an application on the internet is a single line in the job spec.",[17,18,20],"h2",{"id":19},"the-shortest-path","The shortest path",[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],{},"With that the cluster does three things in sequence:",[95,96,97,105,108],"ol",{},[98,99,100,101,104],"li",{},"Resolves the host ",[29,102,103],{},"api.exemplo.com"," to any healthy allocation of the job.",[98,106,107],{},"Requests a valid certificate for that domain on the first request.",[98,109,110],{},"Renews that certificate before expiry, with no intervention.",[10,112,113,114,116],{},"You only need to point the DNS for ",[29,115,103],{}," to the server node IPs. The rest runs by itself.",[17,118,120],{"id":119},"how-the-certificate-is-issued","How the certificate is issued",[10,122,123],{},"HeroCtl uses Let's Encrypt as the default certificate authority. Behind that there are two supported validation mechanisms.",[125,126,128],"h3",{"id":127},"http-01-default","HTTP-01 (default)",[10,130,131,132,135],{},"Works for any public domain that points to the cluster. When an authority asks for proof of ownership, the integrated router responds at the ",[29,133,134],{},"\u002F.well-known\u002Facme-challenge\u002F"," path automatically. Nothing needs to be configured.",[137,138,139],"blockquote",{},[10,140,141,145],{},[142,143,144],"strong",{},"Warning:"," HTTP-01 requires port 80 to be externally accessible. If the firewall blocks 80, issuance fails.",[125,147,149],{"id":148},"dns-01-for-wildcards","DNS-01 (for wildcards)",[10,151,152,153,156],{},"If you need a wildcard certificate (",[29,154,155],{},"*.exemplo.com","), use DNS-01. Configure the DNS provider in the cluster spec:",[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],{},"Natively supported providers: Cloudflare, Route53, DigitalOcean, Hostinger, Hetzner. Others go through an external plugin.",[10,210,211],{},"With DNS-01 active, just declare:",[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},"http-https-redirect","HTTP → HTTPS redirect",[10,245,246,247,250],{},"When ",[29,248,249],{},"tls: true",", all traffic arriving on port 80 is redirected with 301 to 443. You do not need to duplicate configuration.",[10,252,253],{},"To force 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],{},"Do not enable ",[29,333,334],{},"preload"," without understanding the commitment. It is hard to reverse.",[17,337,339],{"id":338},"multiple-domains-for-the-same-app","Multiple domains for the same app",[10,341,342,343,346,347,350],{},"Common pattern: ",[29,344,345],{},"www.exemplo.com"," and ",[29,348,349],{},"exemplo.com"," pointing to the same application, with one being canonical.",[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],{},"Each domain in ",[29,398,399],{},"redirect_from"," gets its own certificate and answers 301 to the canonical ",[29,402,403],{},"host",".",[17,406,408],{"id":407},"path-based-routing","Path-based routing",[10,410,411],{},"Same host, different applications on different paths:",[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,404],{},"The router resolves precedence by specificity. ",[29,504,505],{},"\u002Fapi\u002Fusers"," lands in ",[29,508,509],{},"api-publica",". ",[29,512,513],{},"\u002Fsobre",[29,515,516],{},"site-marketing",[17,518,520],{"id":519},"custom-headers","Custom headers",[10,522,523],{},"To add or remove headers in the response:",[22,525,527],{"className":24,"code":526,"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,528,529,535,543,551,558,565,575,585,595,602,610],{"__ignoreMap":27},[32,530,531,533],{"class":34,"line":35},[32,532,53],{"class":38},[32,534,56],{"class":42},[32,536,537,539,541],{"class":34,"line":50},[32,538,62],{"class":38},[32,540,43],{"class":42},[32,542,67],{"class":46},[32,544,545,547,549],{"class":34,"line":59},[32,546,84],{"class":38},[32,548,43],{"class":42},[32,550,90],{"class":89},[32,552,553,556],{"class":34,"line":70},[32,554,555],{"class":38},"  headers",[32,557,56],{"class":42},[32,559,560,563],{"class":34,"line":81},[32,561,562],{"class":38},"    add",[32,564,56],{"class":42},[32,566,567,570,572],{"class":34,"line":299},[32,568,569],{"class":38},"      X-Frame-Options",[32,571,43],{"class":42},[32,573,574],{"class":46},"DENY\n",[32,576,577,580,582],{"class":34,"line":310},[32,578,579],{"class":38},"      X-Content-Type-Options",[32,581,43],{"class":42},[32,583,584],{"class":46},"nosniff\n",[32,586,587,590,592],{"class":34,"line":320},[32,588,589],{"class":38},"      Referrer-Policy",[32,591,43],{"class":42},[32,593,594],{"class":46},"strict-origin\n",[32,596,597,600],{"class":34,"line":474},[32,598,599],{"class":38},"    remove",[32,601,56],{"class":42},[32,603,604,607],{"class":34,"line":483},[32,605,606],{"class":42},"      - ",[32,608,609],{"class":46},"Server\n",[32,611,612,614],{"class":34,"line":493},[32,613,606],{"class":42},[32,615,616],{"class":46},"X-Powered-By\n",[17,618,620],{"id":619},"basic-rate-limiting","Basic rate limiting",[10,622,623],{},"First-line defense against abuse:",[22,625,627],{"className":24,"code":626,"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,628,629,635,643,651,658,668,678],{"__ignoreMap":27},[32,630,631,633],{"class":34,"line":35},[32,632,53],{"class":38},[32,634,56],{"class":42},[32,636,637,639,641],{"class":34,"line":50},[32,638,62],{"class":38},[32,640,43],{"class":42},[32,642,67],{"class":46},[32,644,645,647,649],{"class":34,"line":59},[32,646,84],{"class":38},[32,648,43],{"class":42},[32,650,90],{"class":89},[32,652,653,656],{"class":34,"line":70},[32,654,655],{"class":38},"  rate_limit",[32,657,56],{"class":42},[32,659,660,663,665],{"class":34,"line":81},[32,661,662],{"class":38},"    requests_per_second",[32,664,43],{"class":42},[32,666,667],{"class":89},"100\n",[32,669,670,673,675],{"class":34,"line":299},[32,671,672],{"class":38},"    burst",[32,674,43],{"class":42},[32,676,677],{"class":89},"200\n",[32,679,680,683,685],{"class":34,"line":310},[32,681,682],{"class":38},"    by",[32,684,43],{"class":42},[32,686,687],{"class":46},"ip\n",[10,689,690],{},"More elaborate limits (per token, per endpoint, with bypass for partners) belong in the application.",[17,692,694],{"id":693},"troubleshooting","Troubleshooting",[125,696,698],{"id":697},"certificate-was-not-issued","Certificate was not issued",[10,700,701],{},"Check three things, in order:",[703,704,705,721],"table",{},[706,707,708],"thead",{},[709,710,711,715,718],"tr",{},[712,713,714],"th",{},"Symptom",[712,716,717],{},"Likely cause",[712,719,720],{},"What to do",[722,723,724,739,755],"tbody",{},[709,725,726,733,736],{},[727,728,729,732],"td",{},[29,730,731],{},"dial tcp: timeout"," in the challenge log",[727,734,735],{},"Port 80 closed",[727,737,738],{},"Open 80\u002Ftcp inbound on server nodes",[709,740,741,746,749],{},[727,742,743],{},[29,744,745],{},"unauthorized: Invalid response",[727,747,748],{},"DNS points elsewhere",[727,750,751,754],{},[29,752,753],{},"dig +short api.exemplo.com"," should return a server node IP",[709,756,757,762,765],{},[727,758,759],{},[29,760,761],{},"too many failed authorizations",[727,763,764],{},"You hit the Let's Encrypt rate limit",[727,766,767],{},"Wait 1h and review the config before trying again",[10,769,770],{},"Inspect the issuance state:",[22,772,776],{"className":773,"code":774,"language":775,"meta":27,"style":27},"language-bash shiki shiki-themes github-dark-default","heroctl ingress cert-status api.exemplo.com\n","bash",[29,777,778],{"__ignoreMap":27},[32,779,780,784,787,790],{"class":34,"line":35},[32,781,783],{"class":782},"sQhOw","heroctl",[32,785,786],{"class":46}," ingress",[32,788,789],{"class":46}," cert-status",[32,791,792],{"class":46}," api.exemplo.com\n",[125,794,796],{"id":795},"certificate-expired-without-renewing","Certificate expired without renewing",[10,798,799],{},"Renewal runs 30 days before expiry. If you are past that, errors have piled up:",[22,801,803],{"className":773,"code":802,"language":775,"meta":27,"style":27},"heroctl ingress cert-renew api.exemplo.com --force\n",[29,804,805],{"__ignoreMap":27},[32,806,807,809,811,814,817],{"class":34,"line":35},[32,808,783],{"class":782},[32,810,786],{"class":46},[32,812,813],{"class":46}," cert-renew",[32,815,816],{"class":46}," api.exemplo.com",[32,818,819],{"class":89}," --force\n",[10,821,822,823,825],{},"Also check whether ",[29,824,399],{}," still points to the cluster. A domain that was moved to another provider without being removed from the spec breaks renewal silently.",[125,827,829],{"id":828},"intermittent-acme-challenge","Intermittent ACME challenge",[10,831,832],{},"Symptom: sometimes it issues, sometimes it fails. Usually it is DNS round-robin with one IP that does not respond on 80, or a Cloudflare in front in proxy mode. For HTTP-01, the domain needs to resolve directly to the cluster during the challenge. Use DNS-01 if you keep Cloudflare proxy on.",[17,834,836],{"id":835},"next-steps","Next steps",[838,839,840,849],"ul",{},[98,841,842,843,848],{},"Configure ",[844,845,847],"a",{"href":846},"\u002Fen\u002Fdocs\u002Fnetworking\u002Ffirewall","firewall"," to allow only what is needed.",[98,850,851,852,856],{},"Understand the ",[844,853,855],{"href":854},"\u002Fen\u002Fdocs\u002Fsecurity\u002Fsecrets","secrets"," model before injecting DNS tokens into the spec.",[858,859,860],"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":862},[863,864,868,869,870,871,872,873,878],{"id":19,"depth":50,"text":20},{"id":119,"depth":50,"text":120,"children":865},[866,867],{"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":519,"depth":50,"text":520},{"id":619,"depth":50,"text":620},{"id":693,"depth":50,"text":694,"children":874},[875,876,877],{"id":697,"depth":59,"text":698},{"id":795,"depth":59,"text":796},{"id":828,"depth":59,"text":829},{"id":835,"depth":50,"text":836},"rede","How to expose applications on port 443 with certificates issued and renewed automatically, without operating an external router.",false,"md","i-lucide-globe","2026-04-26",{},"\u002Fen\u002Fdocs\u002Fnetworking\u002Fingress-tls",[888],"primeiro-deploy","7 min read",{"title":5,"description":880},"en\u002Fdocs\u002Fnetworking\u002Fingress-tls",[53,893,894,166,895,896],"tls","https","lets-encrypt","network","I1k-bvkrznSh-OLfZzVcz5ZMSNYnZnN6IWU11ORjl-8",[899,905,911,916,920,921,927,932,938,943,948,952,958,962],{"path":900,"title":901,"description":902,"category":903,"order":35,"icon":904},"\u002Fen\u002Fdocs\u002Fapi\u002Fapi-reference","REST API reference","Endpoints, JWT authentication, curl examples, and error patterns of the HeroCtl API.","api","i-lucide-code",{"path":906,"title":907,"description":908,"category":909,"order":35,"icon":910},"\u002Fen\u002Fdocs\u002Fdeploy\u002Ffirst-deploy","Deploy your first app","Bring up a Node.js application with a Postgres database in 50 lines of YAML. Includes health check, rolling deploy, and rollback.","deploy","i-lucide-rocket",{"path":912,"title":913,"description":914,"category":909,"order":50,"icon":915},"\u002Fen\u002Fdocs\u002Fdeploy\u002Frolling-canary-blue-green","Rolling, canary, blue-green, and rainbow","Four deploy strategies. When to use each, with complete examples and honest trade-offs.","i-lucide-git-branch",{"path":846,"title":917,"description":918,"category":879,"order":50,"icon":919},"Firewall configuration","Which ports HeroCtl uses, which need to stay open, and which should never be exposed to the internet.","i-lucide-shield",{"path":886,"title":5,"description":880,"category":879,"order":35,"icon":883},{"path":922,"title":923,"description":924,"category":925,"order":50,"icon":926},"\u002Fen\u002Fdocs\u002Fobservability\u002Fbackup-restore","Backup and restore of cluster state","How to save, schedule, and restore HeroCtl control plane snapshots. Disaster recovery strategy.","observabilidade","i-lucide-archive",{"path":928,"title":929,"description":930,"category":925,"order":35,"icon":931},"\u002Fen\u002Fdocs\u002Fobservability\u002Fmetrics-logs","Metrics and logs","Collect metrics, logs, and traces without standing up an external observability stack. When it's worth it, and when to integrate with an outside tool.","i-lucide-activity",{"path":933,"title":934,"description":935,"category":936,"order":59,"icon":937},"\u002Fen\u002Fdocs\u002Foperations\u002Fcli-reference","Complete CLI reference","All heroctl commands with synopsis, flags, and example. Use as a desk reference.","operacoes","i-lucide-terminal",{"path":939,"title":940,"description":941,"category":936,"order":50,"icon":942},"\u002Fen\u002Fdocs\u002Foperations\u002Ffirst-cluster","Bring up a 3-node cluster","Form a cluster with 3 servers in under 10 minutes. Tolerates 1-node failure with no downtime.","i-lucide-network",{"path":944,"title":945,"description":946,"category":936,"order":35,"icon":947},"\u002Fen\u002Fdocs\u002Foperations\u002Finstallation","Installation","Install HeroCtl on any Linux server with Docker in a single command. Covers prerequisites, bootstrap, and verification.","i-lucide-download",{"path":949,"title":950,"description":951,"category":936,"order":70,"icon":883},"\u002Fen\u002Fdocs\u002Foperations\u002Fmulti-region","Multi-region (planned for Q4 2026)","What to expect from multi-region in HeroCtl, how to run across regions today, and the roadmap through 2027.",{"path":953,"title":954,"description":955,"category":956,"order":50,"icon":957},"\u002Fen\u002Fdocs\u002Fsecurity\u002Frbac","RBAC and access control (Business+)","Role, policy, and token model to limit who can submit, read, and operate the cluster.","seguranca","i-lucide-users",{"path":854,"title":959,"description":960,"category":956,"order":35,"icon":961},"Secret management","How to keep passwords, tokens, and keys outside the job spec, with encryption at rest and versioned rotation.","i-lucide-key",{"path":963,"title":964,"description":965,"category":693,"order":35,"icon":966},"\u002Fen\u002Fdocs\u002Ftroubleshooting\u002Fcommon-problems","Troubleshooting common problems","The 12 most frequent problems in HeroCtl clusters, with symptom, diagnosis, and step-by-step fix.","i-lucide-alert-triangle",1777362181477]