[{"data":1,"prerenderedAt":729},["ShallowReactive",2],{"navigation_docs":3,"-remote-tunnel":144,"-remote-tunnel-surround":724},[4,35,84,109,124,134,139],{"title":5,"path":6,"stem":7,"children":8,"page":34},"Get Started","\u002Fget-started","1.get-started",[9,14,19,24,29],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":15,"path":16,"stem":17,"icon":18},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":20,"path":21,"stem":22,"icon":23},"Quick start","\u002Fget-started\u002Fquickstart","1.get-started\u002F3.quickstart","i-lucide-rocket",{"title":25,"path":26,"stem":27,"icon":28},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F4.project-structure","i-lucide-folder-tree",{"title":30,"path":31,"stem":32,"icon":33},"Dashboard","\u002Fget-started\u002Fdashboard","1.get-started\u002F5.dashboard","i-lucide-layout-dashboard",false,{"title":36,"path":37,"stem":38,"children":39,"page":34},"Concepts","\u002Fconcepts","2.concepts",[40,45,50,55,60,65,69,74,79],{"title":41,"path":42,"stem":43,"icon":44},"Architecture","\u002Fconcepts\u002Farchitecture","2.concepts\u002F1.architecture","i-lucide-layers",{"title":46,"path":47,"stem":48,"icon":49},"Machines","\u002Fconcepts\u002Fmachines","2.concepts\u002F2.machines","i-lucide-server",{"title":51,"path":52,"stem":53,"icon":54},"Colony & users","\u002Fconcepts\u002Fcolony","2.concepts\u002F3.colony","i-lucide-users",{"title":56,"path":57,"stem":58,"icon":59},"Transport","\u002Fconcepts\u002Ftransport","2.concepts\u002F4.transport","i-lucide-network",{"title":61,"path":62,"stem":63,"icon":64},"Configuration","\u002Fconcepts\u002Fconfiguration","2.concepts\u002F5.configuration","i-lucide-settings",{"title":66,"path":67,"stem":68,"icon":23},"Deploy","\u002Fconcepts\u002Fdeploy","2.concepts\u002F6.deploy",{"title":70,"path":71,"stem":72,"icon":73},"Groups","\u002Fconcepts\u002Fgroups","2.concepts\u002F7.groups","i-lucide-boxes",{"title":75,"path":76,"stem":77,"icon":78},"Templates","\u002Fconcepts\u002Ftemplates","2.concepts\u002F8.templates","i-lucide-package-plus",{"title":80,"path":81,"stem":82,"icon":83},"Existing projects","\u002Fconcepts\u002Fexisting-projects","2.concepts\u002F9.existing-projects","i-lucide-folder-open",{"title":85,"path":86,"stem":87,"children":88,"page":34},"Remote","\u002Fremote","3.remote",[89,94,99,104],{"title":90,"path":91,"stem":92,"icon":93},"Remote machines","\u002Fremote\u002Foverview","3.remote\u002F1.overview","i-lucide-cloud",{"title":95,"path":96,"stem":97,"icon":98},"Remote deploy","\u002Fremote\u002Fdeploy","3.remote\u002F2.deploy","i-lucide-send",{"title":100,"path":101,"stem":102,"icon":103},"CI","\u002Fremote\u002Fci","3.remote\u002F3.ci","i-lucide-workflow",{"title":105,"path":106,"stem":107,"icon":108},"Tunnels","\u002Fremote\u002Ftunnel","3.remote\u002F4.tunnel","i-lucide-cable",{"title":110,"path":111,"stem":112,"children":113,"page":34},"Security","\u002Fsecurity","4.security",[114,119],{"title":115,"path":116,"stem":117,"icon":118},"Security model","\u002Fsecurity\u002Fmodel","4.security\u002F1.model","i-lucide-shield",{"title":120,"path":121,"stem":122,"icon":123},"Known issues","\u002Fsecurity\u002Fknown-issues","4.security\u002F2.known-issues","i-lucide-triangle-alert",{"title":125,"path":126,"stem":127,"children":128,"page":34},"Reference","\u002Freference","5.reference",[129],{"title":130,"path":131,"stem":132,"icon":133},"CLI reference","\u002Freference\u002Fcli","5.reference\u002F1.cli","i-lucide-terminal",{"title":135,"path":136,"stem":137,"icon":138},"Changelog","\u002Fchangelog","changelog","i-lucide-history",{"title":140,"path":141,"stem":142,"icon":143},"Communities","\u002Fcommunities","communities","i-lucide-heart-handshake",{"id":145,"title":105,"body":146,"description":716,"extension":717,"links":718,"meta":719,"navigation":720,"path":106,"seo":721,"stem":107,"__hash__":723},"docs\u002F3.remote\u002F4.tunnel.md",{"type":147,"value":148,"toc":706},"minimark",[149,167,182,211,216,224,263,277,281,295,361,367,370,384,411,415,451,457,460,500,504,606,609,615,696,702],[150,151,152,153,157,158,161,162,166],"p",{},"A tunnel makes a ",[154,155,156],"strong",{},"loopback-bound container port on a machine"," reachable from\n",[154,159,160],{},"your machine",", over iroh. It opens no port on the machine's network\ninterfaces and needs no firewall change: the only listener it creates is on\nyour side, bound to ",[163,164,165],"code",{},"127.0.0.1",".",[150,168,169,170,173,174,177,178,181],{},"It is a ",[154,171,172],{},"local forward",": the ",[163,175,176],{},"ssh -L"," shape, not a reverse tunnel. Every\nconnection is dialed ",[154,179,180],{},"local → remote","; the machine's worker never dials back\nto you.",[183,184,189],"pre",{"className":185,"code":186,"language":187,"meta":188,"style":188},"language-sh shiki shiki-themes material-theme-lighter github-light github-dark","ant nest tunnel --machine prod --container app-local --port 8080\n# Forwarding 127.0.0.1:8080 -> prod container app-local:8080 over iroh; Ctrl-C to stop\ncurl http:\u002F\u002F127.0.0.1:8080\n","sh","",[163,190,191,199,205],{"__ignoreMap":188},[192,193,196],"span",{"class":194,"line":195},"line",1,[192,197,198],{},"ant nest tunnel --machine prod --container app-local --port 8080\n",[192,200,202],{"class":194,"line":201},2,[192,203,204],{},"# Forwarding 127.0.0.1:8080 -> prod container app-local:8080 over iroh; Ctrl-C to stop\n",[192,206,208],{"class":194,"line":207},3,[192,209,210],{},"curl http:\u002F\u002F127.0.0.1:8080\n",[212,213,215],"h2",{"id":214},"how-it-works","How it works",[183,217,222],{"className":218,"code":220,"language":221},[219],"language-text"," your machine (CLI or ant ui)                    remote machine (ant-worker)\n ┌───────────────────────────────┐               ┌──────────────────────────────────────────┐\n │  curl 127.0.0.1:18080         │               │                                          │\n │        │                      │    iroh       │  net.Dial(\"127.0.0.1:8080\")              │\n │        ▼                      │    stream     │        ▲                                 │\n │  listener on 127.0.0.1:18080 ─┼──────────────►│  worker ─┴─► app container               │\n │        ▲                      │◄──────────────┼─── bytes both ways                       │\n └────────┴──────────────────────┘               └──────────────────────────────────────────┘\n","text",[163,223,220],{"__ignoreMap":188},[225,226,227,247,257,260],"ol",{},[228,229,230,231,234,235,238,239,242,243,246],"li",{},"Your side (the ",[163,232,233],{},"ant"," CLI process, or the ",[163,236,237],{},"ant ui"," process for the dashboard's\n",[154,240,241],{},"Tunnel"," button) binds ",[163,244,245],{},"127.0.0.1:\u003Clocal>",", the only port opened.",[228,248,249,250,253,254,166],{},"Something on your machine connects to that port. For each connection, ant\ndials the worker over iroh (a raw stream on the ",[163,251,252],{},"ant-tunnel\u002F1"," ALPN, separate\nfrom RPC framing) and writes the target line ",[163,255,256],{},"container:port",[228,258,259],{},"The worker authorizes the caller against the machine's roster, resolves the\ntarget to a port ant published on the machine's loopback for a container ant\nmanages, and dials it locally.",[228,261,262],{},"Bytes are piped both ways, your local connection ↔ iroh stream ↔ the\ncontainer. Responses retrace the same path.",[150,264,265,266,269,270,273,274,166],{},"The ",[154,267,268],{},"container port"," is the target, not the published host port. A service\npublished as ",[163,271,272],{},"127.0.0.1:18080->80\u002Ftcp"," is reached with ",[163,275,276],{},"--port 80",[212,278,280],{"id":279},"cli","CLI",[183,282,284],{"className":185,"code":283,"language":187,"meta":188,"style":188},"ant nest tunnel --machine prod --container app-local --port 8080\nant nest tunnel --machine prod --container app-local --port 8080 --local 18080\n",[163,285,286,290],{"__ignoreMap":188},[192,287,288],{"class":194,"line":195},[192,289,198],{},[192,291,292],{"class":194,"line":201},[192,293,294],{},"ant nest tunnel --machine prod --container app-local --port 8080 --local 18080\n",[296,297,298,311],"table",{},[299,300,301],"thead",{},[302,303,304,308],"tr",{},[305,306,307],"th",{},"Flag",[305,309,310],{},"Meaning",[312,313,314,325,338,348],"tbody",{},[302,315,316,322],{},[317,318,319],"td",{},[163,320,321],{},"--machine M",[317,323,324],{},"The machine to tunnel to. Required; the local machine is refused (reach it directly).",[302,326,327,332],{},[317,328,329],{},[163,330,331],{},"--container NAME",[317,333,334,335,166],{},"An ant-managed container name, as shown by ",[163,336,337],{},"ant nest containers list --machine M",[302,339,340,345],{},[317,341,342],{},[163,343,344],{},"--port P",[317,346,347],{},"The container port to reach (not the host port).",[302,349,350,355],{},[317,351,352],{},[163,353,354],{},"--local L",[317,356,357,358,166],{},"Local port to listen on. Defaults to ",[163,359,360],{},"--port",[150,362,363,366],{},[163,364,365],{},"Ctrl-C"," closes the listener and every live connection. The tunnel lives as long\nas the process does; an established connection is not cut for being quiet.",[212,368,30],{"id":369},"dashboard",[150,371,372,373,376,377,380,381,383],{},"On a ",[154,374,375],{},"remote"," machine's page (",[154,378,379],{},"Nest → machine → Containers","), a running\ncontainer's row has a ",[154,382,241],{}," action:",[385,386,387,390,401],"ul",{},[228,388,389],{},"the container port is prefilled from the published ports; a local port is\noptional (a free one is picked when empty);",[228,391,392,393,396,397,400],{},"open tunnels for that machine are listed with a clickable\n",[163,394,395],{},"http:\u002F\u002F127.0.0.1:\u003Cport>"," link and a ",[154,398,399],{},"Stop"," button;",[228,402,403,404,406,407,410],{},"the listener is created by the ",[163,405,237],{}," process, so the URL resolves only on\nthe machine running the dashboard, and ",[154,408,409],{},"creation is refused for a\nnon-loopback caller"," (a browser on another device gets a clear error rather\nthan an unreachable port).",[212,412,414],{"id":413},"what-can-be-the-target","What can be the target",[385,416,417,423,433,448],{},[228,418,419,422],{},[154,420,421],{},"A registered remote machine."," Local-machine tunnels are refused.",[228,424,425,428,429,432],{},[154,426,427],{},"An ant-managed container",", running and publishing the requested port on\nthe machine's loopback. Deploys publish loopback-only by default\n(",[163,430,431],{},"deploy.publish: loopback","), so this is the normal case.",[228,434,435,436,439,440,443,444,447],{},"A container published on ",[154,437,438],{},"every interface"," (",[163,441,442],{},"deploy.publish: all",", or\n",[163,445,446],{},"--publish-all",") has no loopback binding, so the worker refuses it. That is\nnot a loss: reach it directly over the network instead.",[228,449,450],{},"Tunneling to a stopped container fails; the dashboard only offers the action on\na running container's row.",[150,452,453,454,166],{},"The worker refuses anything else. A tunnel can never reach the docker socket,\nCaddy's admin API, SSH, or another local listener; see\n",[455,456,115],"a",{"href":116},[212,458,110],{"id":459},"security",[385,461,462,491,494],{},[228,463,464,465,468,469,472,473,472,476,479,480,483,484,487,488,490],{},"Opening a tunnel needs the ",[154,466,467],{},"deploy"," capability on that machine\n(",[163,470,471],{},"deployer",", ",[163,474,475],{},"ci",[163,477,478],{},"admin",", or ",[163,481,482],{},"owner","), the same trust as running a container\nthere. The worker authorizes every stream; a denied one is recorded in the\naudit log, and a successful open is recorded as ",[163,485,486],{},"tunnel.open"," with the\n",[163,489,256],{}," detail.",[228,492,493],{},"The caller authenticates with their account NodeID; there is no password and\nno inbound port.",[228,495,496,497,499],{},"The local listener binds ",[163,498,165],{}," only, so other devices cannot use the\ntunnel even if they can reach your machine.",[212,501,503],{"id":502},"limits-and-troubleshooting","Limits and troubleshooting",[296,505,506,516],{},[299,507,508],{},[302,509,510,513],{},[305,511,512],{},"Symptom",[305,514,515],{},"Cause \u002F fix",[312,517,518,530,540,553,561,575,587],{},[302,519,520,525],{},[317,521,522],{},[163,523,524],{},"invalid container name",[317,526,527,528,166],{},"Use the name from ",[163,529,337],{},[302,531,532,537],{},[317,533,534],{},[163,535,536],{},"container \"x\" does not publish port N on loopback",[317,538,539],{},"Wrong port (pass the container port, not the host port), the container is stopped, or it was published on all interfaces (connect directly instead).",[302,541,542,547],{},[317,543,544],{},[163,545,546],{},"local port 18080: ... address already in use",[317,548,549,550,166],{},"Another process (or tunnel) owns the port; pick another or omit ",[163,551,552],{},"--local",[302,554,555,558],{},[317,556,557],{},"Tunnel opens, requests fail immediately",[317,559,560],{},"The port is published but the app inside is not listening on it; check the container's logs.",[302,562,563,569],{},[317,564,565,566,568],{},"No ",[154,567,241],{}," button in the dashboard",[317,570,571,572,574],{},"The machine is the local one, the container is stopped, or the dashboard binary predates the feature (",[163,573,237],{}," logs the version).",[302,576,577,580],{},[317,578,579],{},"403 \"tunnels are managed from the machine running this dashboard\"",[317,581,582,583,586],{},"The dashboard is bound non-loopback and you are using it from another device; run ",[163,584,585],{},"ant nest tunnel"," on that device, or use the dashboard on its host.",[302,588,589,595],{},[317,590,591,594],{},[163,592,593],{},"transport: unsupported"," \u002F \"iroh unavailable\"",[317,596,597,598,601,602,605],{},"The binary was built without the transport (",[163,599,600],{},"CGO_ENABLED=0","); remote features need the Linux + CGO build (see ",[455,603,56],{"href":604},"\u002Fconcepts\u002Ftransport#build-tags",").",[150,607,608],{},"Each accepted connection opens one tunnel connection to the worker, closed when\neither end ends. Interactive use is fine; a workload that opens hundreds of\nconcurrent connections is better served by deploying the service normally.",[212,610,612,613],{"id":611},"compared-with-ssh-l","Compared with ",[163,614,176],{},[296,616,617,632],{},[299,618,619],{},[302,620,621,623,627],{},[305,622],{},[305,624,625],{},[163,626,585],{},[305,628,629],{},[163,630,631],{},"ssh -L L:localhost:P host",[312,633,634,648,658,669,680],{},[302,635,636,639,645],{},[317,637,638],{},"Listener",[317,640,641,642,644],{},"Local ",[163,643,165],{}," only",[317,646,647],{},"Local only (by default)",[302,649,650,653,656],{},[317,651,652],{},"Initiator",[317,654,655],{},"Local",[317,657,655],{},[302,659,660,663,666],{},[317,661,662],{},"Authentication",[317,664,665],{},"Account NodeID + machine roster role",[317,667,668],{},"SSH keys\u002Faccounts",[302,670,671,674,677],{},[317,672,673],{},"Target",[317,675,676],{},"An ant-managed container's published loopback port",[317,678,679],{},"Any host\u002Fport the SSH server can dial",[302,681,682,685,691],{},[317,683,684],{},"Machine-side agent",[317,686,687,690],{},[163,688,689],{},"ant-worker"," (no SSH required)",[317,692,693],{},[163,694,695],{},"sshd",[150,697,698,699,166],{},"There is no reverse mode: to expose a service on your machine to the remote\nhost, ant has no equivalent of ",[163,700,701],{},"ssh -R",[703,704,705],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":188,"searchDepth":201,"depth":201,"links":707},[708,709,710,711,712,713,714],{"id":214,"depth":201,"text":215},{"id":279,"depth":201,"text":280},{"id":369,"depth":201,"text":30},{"id":413,"depth":201,"text":414},{"id":459,"depth":201,"text":110},{"id":502,"depth":201,"text":503},{"id":611,"depth":201,"text":715},"Compared with ssh -L","Reach a managed container port from your machine: no inbound port on either side.","md",null,{},{"icon":108},{"title":105,"description":722},"Forward a local port to an ant-managed container port over iroh, from the CLI or the dashboard.","yK9NnMS_T4Pch22Ehyw3d3LgHKLSSMFSExkj7OeXCrs",[725,727],{"title":100,"path":101,"stem":102,"description":726,"icon":103,"children":-1},"Deploy to a machine from a CI pipeline.",{"title":115,"path":116,"stem":117,"description":728,"icon":118,"children":-1},"How Ant authenticates, authorizes, and limits what a peer can do.",1791494557151]