[{"data":1,"prerenderedAt":2249},["ShallowReactive",2],{"navigation_docs":3,"-guides-run-remote-access":504,"-guides-run-remote-access-surround":2244},[4,28,51,187,214,469],{"title":5,"path":6,"stem":7,"children":8},"Get started","\u002Fget-started","1.get-started",[9,12,16,20,24],{"title":10,"path":6,"stem":11},"Overview","1.get-started\u002Findex",{"title":13,"path":14,"stem":15},"Why Kraft","\u002Fget-started\u002Fwhy-kraft","1.get-started\u002F0.why-kraft",{"title":17,"path":18,"stem":19},"Install","\u002Fget-started\u002Finstall","1.get-started\u002F1.install",{"title":21,"path":22,"stem":23},"Your first work item","\u002Fget-started\u002Ffirst-work-item","1.get-started\u002F2.first-work-item",{"title":25,"path":26,"stem":27},"FAQ","\u002Fget-started\u002Ffaq","1.get-started\u002F3.faq",{"title":29,"path":30,"stem":31,"children":32},"Concepts","\u002Fconcepts","2.concepts",[33,35,39,43,47],{"title":10,"path":30,"stem":34},"2.concepts\u002Findex",{"title":36,"path":37,"stem":38},"How a work item runs","\u002Fconcepts\u002Fhow-a-work-item-runs","2.concepts\u002F1.how-a-work-item-runs",{"title":40,"path":41,"stem":42},"Caps and budgets","\u002Fconcepts\u002Fcaps-and-budgets","2.concepts\u002F2.caps-and-budgets",{"title":44,"path":45,"stem":46},"Why a permission gate","\u002Fconcepts\u002Fpermission-gate","2.concepts\u002F3.permission-gate",{"title":48,"path":49,"stem":50},"Vocabulary","\u002Fconcepts\u002Fvocabulary","2.concepts\u002F4.vocabulary",{"title":52,"path":53,"stem":54,"children":55},"Guides","\u002Fguides","3.guides",[56,58,96,113,134,183],{"title":10,"path":53,"stem":57},"3.guides\u002Findex",{"title":59,"path":60,"stem":61,"children":62,"page":95},"Day to day","\u002Fguides\u002Fday-to-day","3.guides\u002F1.day-to-day",[63,67,71,75,79,83,87,91],{"title":64,"path":65,"stem":66},"The setup wizard on first start","\u002Fguides\u002Fday-to-day\u002Ffirst-run","3.guides\u002F1.day-to-day\u002F2.first-run",{"title":68,"path":69,"stem":70},"File a work item","\u002Fguides\u002Fday-to-day\u002Ffile-a-work-item","3.guides\u002F1.day-to-day\u002F3.file-a-work-item",{"title":72,"path":73,"stem":74},"Use Kraft from your agent","\u002Fguides\u002Fday-to-day\u002Fagent-integration","3.guides\u002F1.day-to-day\u002F4.agent-integration",{"title":76,"path":77,"stem":78},"Reviewing a change","\u002Fguides\u002Fday-to-day\u002Freview-a-change","3.guides\u002F1.day-to-day\u002F5.review-a-change",{"title":80,"path":81,"stem":82},"Raise a cap on a stopped item","\u002Fguides\u002Fday-to-day\u002Fraise-a-cap","3.guides\u002F1.day-to-day\u002F6.raise-a-cap",{"title":84,"path":85,"stem":86},"Kraft for VS Code","\u002Fguides\u002Fday-to-day\u002Fvscode","3.guides\u002F1.day-to-day\u002F7.vscode",{"title":88,"path":89,"stem":90},"Kraft on a phone","\u002Fguides\u002Fday-to-day\u002Fkraft-on-a-phone","3.guides\u002F1.day-to-day\u002F8.kraft-on-a-phone",{"title":92,"path":93,"stem":94},"Get notified when an item needs you","\u002Fguides\u002Fday-to-day\u002Fnotifications","3.guides\u002F1.day-to-day\u002F9.notifications",false,{"title":97,"path":98,"stem":99,"children":100,"page":95},"Customize and automate","\u002Fguides\u002Fcustomize","3.guides\u002F2.customize",[101,105,109],{"title":102,"path":103,"stem":104},"Write your own chain","\u002Fguides\u002Fcustomize\u002Fwrite-your-own-chain","3.guides\u002F2.customize\u002F1.write-your-own-chain",{"title":106,"path":107,"stem":108},"Add a security review or a gate reviewer","\u002Fguides\u002Fcustomize\u002Fadd-review-agents","3.guides\u002F2.customize\u002F2.add-review-agents",{"title":110,"path":111,"stem":112},"Schedule or webhook work","\u002Fguides\u002Fcustomize\u002Fschedule-and-webhook-work","3.guides\u002F2.customize\u002F3.schedule-and-webhook-work",{"title":114,"path":115,"stem":116,"children":117,"page":95},"Agents and harnesses","\u002Fguides\u002Fharnesses","3.guides\u002F3.harnesses",[118,122,126,130],{"title":119,"path":120,"stem":121},"Switch a task to another harness","\u002Fguides\u002Fharnesses\u002Fswitch-harness","3.guides\u002F3.harnesses\u002F1.switch-harness",{"title":123,"path":124,"stem":125},"Add or override a harness","\u002Fguides\u002Fharnesses\u002Fadding-a-harness","3.guides\u002F3.harnesses\u002F2.adding-a-harness",{"title":127,"path":128,"stem":129},"Build a worker Kit","\u002Fguides\u002Fharnesses\u002Fworker-kit","3.guides\u002F3.harnesses\u002F3.worker-kit",{"title":131,"path":132,"stem":133},"Give a worker its login","\u002Fguides\u002Fharnesses\u002Fgive-a-worker-its-login","3.guides\u002F3.harnesses\u002F4.give-a-worker-its-login",{"title":135,"path":136,"stem":137,"children":138,"page":95},"Run the server","\u002Fguides\u002Frun","3.guides\u002F4.run",[139,143,147,151,155,159,163,167,171,175,179],{"title":140,"path":141,"stem":142},"Remote access","\u002Fguides\u002Frun\u002Fremote-access","3.guides\u002F4.run\u002F01.remote-access",{"title":144,"path":145,"stem":146},"Put a proxy in front of Kraft","\u002Fguides\u002Frun\u002Fput-a-proxy-in-front-of-kraft","3.guides\u002F4.run\u002F02.put-a-proxy-in-front-of-kraft",{"title":148,"path":149,"stem":150},"Restart Kraft without ending running agents","\u002Fguides\u002Frun\u002Frestart-kraft","3.guides\u002F4.run\u002F03.restart-kraft",{"title":152,"path":153,"stem":154},"Back up and restore the database","\u002Fguides\u002Frun\u002Fback-up-and-restore","3.guides\u002F4.run\u002F04.back-up-and-restore",{"title":156,"path":157,"stem":158},"Logs and disk space","\u002Fguides\u002Frun\u002Flogs-and-disk-space","3.guides\u002F4.run\u002F05.logs-and-disk-space",{"title":160,"path":161,"stem":162},"Run Kraft as a service","\u002Fguides\u002Frun\u002Frun-as-a-service","3.guides\u002F4.run\u002F06.run-as-a-service",{"title":164,"path":165,"stem":166},"Upgrade Kraft","\u002Fguides\u002Frun\u002Fupgrade-kraft","3.guides\u002F4.run\u002F07.upgrade-kraft",{"title":168,"path":169,"stem":170},"Upgrade your configuration","\u002Fguides\u002Frun\u002Fupgrade-your-configuration","3.guides\u002F4.run\u002F08.upgrade-your-configuration",{"title":172,"path":173,"stem":174},"Upgrade from 1.4","\u002Fguides\u002Frun\u002Fupgrade-from-1-4","3.guides\u002F4.run\u002F09.upgrade-from-1-4",{"title":176,"path":177,"stem":178},"Upgrade from 0.x or a release candidate","\u002Fguides\u002Frun\u002Fupgrade-from-0-x-or-a-release-candidate","3.guides\u002F4.run\u002F10.upgrade-from-0-x-or-a-release-candidate",{"title":180,"path":181,"stem":182},"Roll back to 1.4","\u002Fguides\u002Frun\u002Froll-back","3.guides\u002F4.run\u002F11.roll-back",{"title":184,"path":185,"stem":186},"Kraft Lite","\u002Fguides\u002Fkraft-lite","3.guides\u002F5.kraft-lite",{"title":188,"path":189,"stem":190,"children":191},"Troubleshooting","\u002Ftroubleshooting","4.troubleshooting",[192,194,198,202,206,210],{"title":10,"path":189,"stem":193},"4.troubleshooting\u002Findex",{"title":195,"path":196,"stem":197},"Why did my item stop?","\u002Ftroubleshooting\u002Fwhy-did-my-item-stop","4.troubleshooting\u002F1.why-did-my-item-stop",{"title":199,"path":200,"stem":201},"Stop reasons in detail","\u002Ftroubleshooting\u002Fstop-reasons-in-detail","4.troubleshooting\u002F2.stop-reasons-in-detail",{"title":203,"path":204,"stem":205},"Starting and reaching Kraft","\u002Ftroubleshooting\u002Fstarting-and-reaching-kraft","4.troubleshooting\u002F3.starting-and-reaching-kraft",{"title":207,"path":208,"stem":209},"Doctor failures","\u002Ftroubleshooting\u002Fdoctor-failures","4.troubleshooting\u002F4.doctor-failures",{"title":211,"path":212,"stem":213},"Sandbox and Kit stops","\u002Ftroubleshooting\u002Fsandbox-and-kit-stops","4.troubleshooting\u002F5.sandbox-and-kit-stops",{"title":215,"path":216,"stem":217,"children":218},"Reference","\u002Freference","5.reference",[219,221,259,281,285,375,393,419,423,427,461,465],{"title":10,"path":216,"stem":220},"5.reference\u002Findex",{"title":222,"path":223,"stem":224,"children":225},"Web UI","\u002Freference\u002Fweb-ui","5.reference\u002F00.web-ui\u002Findex",[226,227,231,235,239,243,247,251,255],{"title":10,"path":223,"stem":224},{"title":228,"path":229,"stem":230},"Sidebar, search, and keyboard","\u002Freference\u002Fweb-ui\u002Fsidebar-search-and-keyboard","5.reference\u002F00.web-ui\u002F0.sidebar-search-and-keyboard",{"title":232,"path":233,"stem":234},"The board","\u002Freference\u002Fweb-ui\u002Fboard","5.reference\u002F00.web-ui\u002F1.board",{"title":236,"path":237,"stem":238},"An item's page","\u002Freference\u002Fweb-ui\u002Fitem-page","5.reference\u002F00.web-ui\u002F2.item-page",{"title":240,"path":241,"stem":242},"Fix loops and test scopes","\u002Freference\u002Fweb-ui\u002Ffix-loops-and-test-scopes","5.reference\u002F00.web-ui\u002F3.fix-loops-and-test-scopes",{"title":244,"path":245,"stem":246},"Config before an item starts","\u002Freference\u002Fweb-ui\u002Fconfig-before-start","5.reference\u002F00.web-ui\u002F4.config-before-start",{"title":248,"path":249,"stem":250},"The review page","\u002Freference\u002Fweb-ui\u002Freview-page","5.reference\u002F00.web-ui\u002F5.review-page",{"title":252,"path":253,"stem":254},"Templates and Settings","\u002Freference\u002Fweb-ui\u002Ftemplates-and-settings","5.reference\u002F00.web-ui\u002F6.templates-and-settings",{"title":256,"path":257,"stem":258},"Analytics","\u002Freference\u002Fweb-ui\u002Fanalytics","5.reference\u002F00.web-ui\u002F7.analytics",{"title":260,"path":261,"stem":262,"children":263},"CLI","\u002Freference\u002Fcli","5.reference\u002F01.cli\u002Findex",[264,265,269,273,277],{"title":10,"path":261,"stem":262},{"title":266,"path":267,"stem":268},"Item verbs","\u002Freference\u002Fcli\u002Fitem","5.reference\u002F01.cli\u002F2.item",{"title":270,"path":271,"stem":272},"View verbs","\u002Freference\u002Fcli\u002Fview","5.reference\u002F01.cli\u002F3.view",{"title":274,"path":275,"stem":276},"Repo verbs","\u002Freference\u002Fcli\u002Frepo","5.reference\u002F01.cli\u002F4.repo",{"title":278,"path":279,"stem":280},"Admin verbs","\u002Freference\u002Fcli\u002Fadmin","5.reference\u002F01.cli\u002F5.admin",{"title":282,"path":283,"stem":284},"Work item statuses","\u002Freference\u002Fstatuses","5.reference\u002F02.statuses",{"title":286,"path":287,"stem":288,"children":289},"Configuration","\u002Freference\u002Fconfiguration","5.reference\u002F03.configuration\u002Findex",[290,291,309,313,317,321,325,329,333,337,371],{"title":10,"path":287,"stem":288},{"title":292,"path":293,"stem":294,"children":295},"repos.yaml","\u002Freference\u002Fconfiguration\u002Frepos","5.reference\u002F03.configuration\u002F02.repos\u002Findex",[296,297,301,305],{"title":10,"path":293,"stem":294},{"title":298,"path":299,"stem":300},"How connect proposes commands","\u002Freference\u002Fconfiguration\u002Frepos\u002Fconnect-proposals","5.reference\u002F03.configuration\u002F02.repos\u002F1.connect-proposals",{"title":302,"path":303,"stem":304},"detectors.yaml","\u002Freference\u002Fconfiguration\u002Frepos\u002Fdetectors","5.reference\u002F03.configuration\u002F02.repos\u002F2.detectors",{"title":306,"path":307,"stem":308},"Workspaces","\u002Freference\u002Fconfiguration\u002Frepos\u002Fworkspaces","5.reference\u002F03.configuration\u002F02.repos\u002F3.workspaces",{"title":310,"path":311,"stem":312},"policy.yaml","\u002Freference\u002Fconfiguration\u002Fpolicy","5.reference\u002F03.configuration\u002F03.policy",{"title":314,"path":315,"stem":316},"Library and chains","\u002Freference\u002Fconfiguration\u002Flibrary-and-chains","5.reference\u002F03.configuration\u002F04.library-and-chains",{"title":318,"path":319,"stem":320},"harnesses.yaml","\u002Freference\u002Fconfiguration\u002Fharnesses-file","5.reference\u002F03.configuration\u002F05.harnesses-file",{"title":322,"path":323,"stem":324},"access.yaml","\u002Freference\u002Fconfiguration\u002Faccess","5.reference\u002F03.configuration\u002F06.access",{"title":326,"path":327,"stem":328},"intake.yaml","\u002Freference\u002Fconfiguration\u002Fintake","5.reference\u002F03.configuration\u002F07.intake",{"title":330,"path":331,"stem":332},"notify.yaml","\u002Freference\u002Fconfiguration\u002Fnotify","5.reference\u002F03.configuration\u002F08.notify",{"title":334,"path":335,"stem":336},"theme.yaml","\u002Freference\u002Fconfiguration\u002Ftheme","5.reference\u002F03.configuration\u002F09.theme",{"title":338,"path":339,"stem":340,"children":341},"Sandboxed workers","\u002Freference\u002Fconfiguration\u002Fsandbox","5.reference\u002F03.configuration\u002F10.sandbox\u002Findex",[342,343,347,351,355,359,363,367],{"title":10,"path":339,"stem":340},{"title":344,"path":345,"stem":346},"Resource limits","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fresource-limits","5.reference\u002F03.configuration\u002F10.sandbox\u002F1.resource-limits",{"title":348,"path":349,"stem":350},"Callbacks from a sandbox","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fcallbacks","5.reference\u002F03.configuration\u002F10.sandbox\u002F2.callbacks",{"title":352,"path":353,"stem":354},"Network policy","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fnetwork-policy","5.reference\u002F03.configuration\u002F10.sandbox\u002F3.network-policy",{"title":356,"path":357,"stem":358},"Credentials","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fcredentials","5.reference\u002F03.configuration\u002F10.sandbox\u002F4.credentials",{"title":360,"path":361,"stem":362},"Kits","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fkits","5.reference\u002F03.configuration\u002F10.sandbox\u002F5.kits",{"title":364,"path":365,"stem":366},"sandbox.yaml","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fsandbox-yaml","5.reference\u002F03.configuration\u002F10.sandbox\u002F6.sandbox-yaml",{"title":368,"path":369,"stem":370},"Git in a sandbox","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fgit-in-a-sandbox","5.reference\u002F03.configuration\u002F10.sandbox\u002F7.git-in-a-sandbox",{"title":372,"path":373,"stem":374},"Environment variables","\u002Freference\u002Fconfiguration\u002Fenvironment-variables","5.reference\u002F03.configuration\u002F11.environment-variables",{"title":376,"path":377,"stem":378,"children":379},"Chain file keys","\u002Freference\u002Fchain-nodes","5.reference\u002F04.chain-nodes\u002Findex",[380,381,385,389],{"title":10,"path":377,"stem":378},{"title":382,"path":383,"stem":384},"Subprocess tasks","\u002Freference\u002Fchain-nodes\u002Fsubprocess-tasks","5.reference\u002F04.chain-nodes\u002F2.subprocess-tasks",{"title":386,"path":387,"stem":388},"Fix loop and judge","\u002Freference\u002Fchain-nodes\u002Ffix-loop","5.reference\u002F04.chain-nodes\u002F3.fix-loop",{"title":390,"path":391,"stem":392},"Result file","\u002Freference\u002Fchain-nodes\u002Fresult-file","5.reference\u002F04.chain-nodes\u002F4.result-file",{"title":394,"path":395,"stem":396,"children":397},"Agent harnesses","\u002Freference\u002Fharnesses","5.reference\u002F05.harnesses\u002Findex",[398,399,403,407,411,415],{"title":10,"path":395,"stem":396},{"title":400,"path":401,"stem":402},"Unattended runs","\u002Freference\u002Fharnesses\u002Funattended-runs","5.reference\u002F05.harnesses\u002F2.unattended-runs",{"title":404,"path":405,"stem":406},"Agent profiles","\u002Freference\u002Fharnesses\u002Fagent-profiles","5.reference\u002F05.harnesses\u002F3.agent-profiles",{"title":408,"path":409,"stem":410},"Harness definition files","\u002Freference\u002Fharnesses\u002Fharness-files","5.reference\u002F05.harnesses\u002F4.harness-files",{"title":412,"path":413,"stem":414},"Fallback and escalation","\u002Freference\u002Fharnesses\u002Ffallback-and-escalation","5.reference\u002F05.harnesses\u002F5.fallback-and-escalation",{"title":416,"path":417,"stem":418},"Cost reporting","\u002Freference\u002Fharnesses\u002Fcost-reporting","5.reference\u002F05.harnesses\u002F6.cost-reporting",{"title":420,"path":421,"stem":422},"Permission gate","\u002Freference\u002Fpermissions","5.reference\u002F06.permissions",{"title":424,"path":425,"stem":426},"Inbound triggers","\u002Freference\u002Ftriggers","5.reference\u002F07.triggers",{"title":428,"path":429,"stem":430,"children":431},"HTTP API","\u002Freference\u002Fhttp-api","5.reference\u002F08.http-api\u002Findex",[432,433,437,441,445,449,453,457],{"title":10,"path":429,"stem":430},{"title":434,"path":435,"stem":436},"Filing, reading and changing work items","\u002Freference\u002Fhttp-api\u002Fwork-items","5.reference\u002F08.http-api\u002F2.work-items",{"title":438,"path":439,"stem":440},"Gates, run control, ending and retry","\u002Freference\u002Fhttp-api\u002Fgates-run-control-and-ending","5.reference\u002F08.http-api\u002F3.gates-run-control-and-ending",{"title":442,"path":443,"stem":444},"The work item object","\u002Freference\u002Fhttp-api\u002Fwork-item-object","5.reference\u002F08.http-api\u002F4.work-item-object",{"title":446,"path":447,"stem":448},"Budget, events, diff and documents","\u002Freference\u002Fhttp-api\u002Fbudget-and-events","5.reference\u002F08.http-api\u002F5.budget-and-events",{"title":450,"path":451,"stem":452},"Repos, chains, harnesses and the server","\u002Freference\u002Fhttp-api\u002Frepos-chains-harnesses-and-server","5.reference\u002F08.http-api\u002F6.repos-chains-harnesses-and-server",{"title":454,"path":455,"stem":456},"Drafts","\u002Freference\u002Fhttp-api\u002Fdrafts","5.reference\u002F08.http-api\u002F7.drafts",{"title":458,"path":459,"stem":460},"Ops for each draft area","\u002Freference\u002Fhttp-api\u002Fdraft-ops","5.reference\u002F08.http-api\u002F8.draft-ops",{"title":462,"path":463,"stem":464},"MCP tools","\u002Freference\u002Fmcp-tools","5.reference\u002F09.mcp-tools",{"title":466,"path":467,"stem":468},"Events","\u002Freference\u002Fevents","5.reference\u002F10.events",{"title":470,"path":471,"stem":472,"children":473},"Security and project","\u002Fproject","6.project",[474,476,480,484,488,492,496,500],{"title":10,"path":471,"stem":475},"6.project\u002Findex",{"title":477,"path":478,"stem":479},"Security","\u002Fproject\u002Fsecurity","6.project\u002F1.security",{"title":481,"path":482,"stem":483},"Data and privacy","\u002Fproject\u002Fdata-and-privacy","6.project\u002F2.data-and-privacy",{"title":485,"path":486,"stem":487},"What's new in 2.0","\u002Fproject\u002Fwhats-new","6.project\u002F3.whats-new",{"title":489,"path":490,"stem":491},"Status and support","\u002Fproject\u002Fstatus-and-support","6.project\u002F4.status-and-support",{"title":493,"path":494,"stem":495},"Architecture","\u002Fproject\u002Farchitecture","6.project\u002F5.architecture",{"title":497,"path":498,"stem":499},"Source map","\u002Fproject\u002Fsource-map","6.project\u002F6.source-map",{"title":501,"path":502,"stem":503},"Contributing","\u002Fproject\u002Fcontributing","6.project\u002F7.contributing",{"id":505,"title":140,"body":506,"description":2237,"extension":2238,"links":2239,"meta":2240,"navigation":2241,"path":141,"seo":2242,"stem":142,"__hash__":2243},"docs\u002F3.guides\u002F4.run\u002F01.remote-access.md",{"type":507,"value":508,"toc":2220},"minimark",[509,513,518,564,573,576,585,598,727,730,738,742,775,785,810,843,846,921,927,930,941,1117,1126,1129,1184,1187,1218,1253,1284,1287,1299,1561,1564,1572,1592,1603,1608,1620,1640,1656,1666,1691,1704,1707,1710,1768,1771,1902,1909,1913,1919,1947,1950,1971,2095,2098,2173,2188,2192,2216],[510,511,512],"p",{},"Reach the Kraft board from a phone or another machine by binding it off\nloopback and turning on password auth. You get the real board, with the same\nauth, at an address you choose.",[514,515,517],"h2",{"id":516},"before-you-start","Before you start",[519,520,521,525,533,547],"ul",{},[522,523,524],"li",{},"A password. Kraft refuses any bind off loopback until one is set.",[522,526,527,528,532],{},"The hostname or address you will type in the other device's browser. It goes\nin ",[529,530,531],"code",{},"allowed_hosts",".",[522,534,535,536,539,540,542,543,546],{},"The port. It is 8765 unless you set ",[529,537,538],{},"port"," in ",[529,541,322],{}," or pass ",[529,544,545],{},"--port",".\nUse your port wherever this page says 8765.",[522,548,549,551,552,555,556,559,560,563],{},[529,550,322],{},", which lives in ",[529,553,554],{},"$KRAFT_CONFIG_DIR"," when you set it, else in\n",[529,557,558],{},"$KRAFT_HOME\u002Fconfig\u002F"," (by default ",[529,561,562],{},"~\u002F.kraft\u002Fconfig\u002F",").",[510,565,566,567,572],{},"Which of these you need depends on the way in you pick. ",[568,569,571],"a",{"href":570},"#choose-a-way","Choose a way","\ncomes next.",[514,574,571],{"id":575},"choose-a-way",[510,577,578,579,582,583,532],{},"Kraft binds ",[529,580,581],{},"127.0.0.1"," by default and skips auth for local clients. Any other\nbind makes Kraft require the password from every client, local ones included,\nand check browser Host headers against ",[529,584,531],{},[510,586,587,588,592,593,597],{},"Pick the narrowest way that works, then follow only its section. The first\nfour end at ",[568,589,591],{"href":590},"#restart-kraft","Restart Kraft"," and ",[568,594,596],{"href":595},"#check-it-worked","Check it worked",".\nThe last, the webhook proxy, needs no restart of Kraft.",[599,600,601,617],"table",{},[602,603,604],"thead",{},[605,606,607,611,614],"tr",{},[608,609,610],"th",{},"Way",[608,612,613],{},"Choose it when",[608,615,616],{},"It needs",[618,619,620,639,657,677,704],"tbody",{},[605,621,622,630,633],{},[623,624,625,629],"td",{},[568,626,628],{"href":627},"#over-tailscale","Over Tailscale"," (recommended)",[623,631,632],{},"Your devices are on one tailnet. Only they can reach the board, and your LAN cannot.",[623,634,635,636,638],{},"Tailscale running before Kraft, a hand edit of ",[529,637,322],{},", and a restart.",[605,640,641,647,650],{},[623,642,643],{},[568,644,646],{"href":645},"#on-your-local-network","On your local network",[623,648,649],{},"The phone and this machine share a network you trust.",[623,651,652,653,656],{},"A ",[529,654,655],{},"0.0.0.0"," bind, which listens on every network this machine is on, and a restart.",[605,658,659,665,668],{},[623,660,661],{},[568,662,664],{"href":663},"#over-a-cloudflare-quick-tunnel","Over a Cloudflare Quick Tunnel",[623,666,667],{},"You cannot use Tailscale, and accept the board on the public internet.",[623,669,670,673,674,676],{},[529,671,672],{},"cloudflared",", a ",[529,675,655],{}," bind, a long random password, and a restart.",[605,678,679,685,688],{},[623,680,681],{},[568,682,684],{"href":683},"#behind-a-reverse-proxy-you-run","Behind a reverse proxy you run",[623,686,687],{},"You run Caddy, nginx or another proxy, and want the board at a name of your own.",[623,689,652,690,692,693,695,696,699,700,703],{},[529,691,655],{}," bind, a password, the name in ",[529,694,531],{},", a proxy that passes ",[529,697,698],{},"Host",", ",[529,701,702],{},"Origin"," and the WebSocket on, and a restart.",[605,705,706,710,717],{},[623,707,708],{},[568,709,144],{"href":145},[623,711,712,713,716],{},"A tunnel or reverse proxy on this machine gets a ",[529,714,715],{},"403"," for every request, and what must pass through is webhooks or scripts, not the board.",[623,718,719,720,722,723,726],{},"The proxy's ",[529,721,698],{}," setting, a password, and an ",[529,724,725],{},"X-Forwarded-For"," the proxy sets itself.",[510,728,729],{},"The path a request takes in each way:",[510,731,732],{},[733,734],"img",{"alt":735,"src":736,"width":737},"Five ways in. Tailscale encrypts the tailnet to a Kraft on the Tailscale address. A local network carries plain http. A Quick Tunnel crosses the public internet at an https URL. Your reverse proxy serves https and passes Host. Those three bind 0.0.0.0, with a password and the name in allowed_hosts. A webhook proxy sets X-Forwarded-For and Host localhost for a loopback Kraft: every API call but health and login needs a session or token.","\u002Fdiagrams\u002Fportrait\u002Fremote-ways.svg",489,[514,739,741],{"id":740},"set-a-password","Set a password",[510,743,744,745,748,749,751,752,756,757,760,761,764,765,767,768,770,771,774],{},"Kraft refuses any bind off loopback until a password is set, both at\n",[529,746,747],{},"kraft admin start"," and on the Settings › Access screen. On ",[529,750,581],{}," the\nscreen lists the password under ",[753,754,755],"strong",{},"Not used on 127.0.0.1",", and picking\n",[753,758,759],{},"Local network"," asks for one: ",[753,762,763],{},"Set and switch"," saves the password and the\n",[529,766,655],{}," bind in one step (on a phone, a ",[753,769,741],{}," sheet does the\nsame). The button reads ",[753,772,773],{},"Switch"," when a password is already set.",[510,776,777,778,780,781,784],{},"Once the bind is off loopback, every browser signs in, including one on the\nmachine itself. Kraft stores only the password's hash, in ",[529,779,322],{},". The\nAccess screen's ",[753,782,783],{},"Password"," card changes it once Kraft is off loopback.",[510,786,787,788,790,791,794,795,798,799,802,803,805,806,809],{},"To set a password and leave the bind alone, send it by itself while Kraft is\nrunning on ",[529,789,581],{},", which is the default. ",[529,792,793],{},"kraft admin health"," shows whether\na server answers; if none does, start one with ",[529,796,797],{},"kraft admin start --detach",". This reads it without echo and passes it through pipes\nbetween built-in and ",[529,800,801],{},"jq"," commands, so it stays out of your shell history and\nthe process list. It needs ",[529,804,801],{},". Run ",[529,807,808],{},"read"," first, type the password, and press\nEnter:",[811,812,817],"pre",{"className":813,"code":814,"language":815,"meta":816,"style":816},"language-bash shiki shiki-themes github-light-high-contrast github-light-high-contrast github-dark-high-contrast","IFS= read -rs PW\n","bash","",[529,818,819],{"__ignoreMap":816},[820,821,824,828,832,836,839],"span",{"class":822,"line":823},"line",1,[820,825,827],{"class":826},"s7iLA","IFS",[820,829,831],{"class":830},"sklAV","=",[820,833,835],{"class":834},"ssYy9"," read",[820,837,838],{"class":834}," -rs",[820,840,842],{"class":841},"semJd"," PW\n",[510,844,845],{},"Then send it and clear it:",[811,847,849],{"className":813,"code":848,"language":815,"meta":816,"style":816},"printf '%s' \"$PW\" | jq -Rs '{password: .}' | curl -X PUT http:\u002F\u002F127.0.0.1:8765\u002Fapi\u002Faccess \\\n  -H 'Content-Type: application\u002Fjson' --data @-\nunset PW\n",[529,850,851,898,913],{"__ignoreMap":816},[820,852,853,856,859,862,865,868,871,875,878,881,883,886,889,892,895],{"class":822,"line":823},[820,854,855],{"class":834},"printf",[820,857,858],{"class":841}," '%s'",[820,860,861],{"class":841}," \"",[820,863,864],{"class":826},"$PW",[820,866,867],{"class":841},"\"",[820,869,870],{"class":830}," |",[820,872,874],{"class":873},"szw1H"," jq",[820,876,877],{"class":834}," -Rs",[820,879,880],{"class":841}," '{password: .}'",[820,882,870],{"class":830},[820,884,885],{"class":873}," curl",[820,887,888],{"class":834}," -X",[820,890,891],{"class":841}," PUT",[820,893,894],{"class":841}," http:\u002F\u002F127.0.0.1:8765\u002Fapi\u002Faccess",[820,896,897],{"class":830}," \\\n",[820,899,901,904,907,910],{"class":822,"line":900},2,[820,902,903],{"class":834},"  -H",[820,905,906],{"class":841}," 'Content-Type: application\u002Fjson'",[820,908,909],{"class":834}," --data",[820,911,912],{"class":841}," @-\n",[820,914,916,919],{"class":822,"line":915},3,[820,917,918],{"class":834},"unset",[820,920,842],{"class":841},[510,922,923,924,532],{},"You know it worked when the reply shows ",[529,925,926],{},"\"password_set\":true",[514,928,628],{"id":929},"over-tailscale",[510,931,932,933,592,935,937,938,940],{},"The Access screen offers only ",[529,934,581],{},[529,936,655],{},", so set a Tailscale\nbind in ",[529,939,322],{}," by hand. Start Tailscale before Kraft: the Tailscale\naddress does not exist until Tailscale is up, and the bind fails without it.",[942,943,944,961,1008,1023,1105,1110],"ol",{},[522,945,946,947,950,951,953,954,956,957,960],{},"Set a password with the commands in ",[568,948,741],{"href":949},"#set-a-password",".\nThey leave the bind on ",[529,952,581],{},". Picking ",[753,955,759],{}," on the Access\nscreen would also set one, but it writes ",[529,958,959],{},"bind: 0.0.0.0"," with it.",[522,962,963,964,967,968,971,972,988,991,992,995,996],{},"Find the machine's Tailscale address and name. ",[529,965,966],{},"tailscale ip -4"," prints the\naddress, such as ",[529,969,970],{},"100.101.102.103",":",[811,973,975],{"className":813,"code":974,"language":815,"meta":816,"style":816},"tailscale ip -4\n",[529,976,977],{"__ignoreMap":816},[820,978,979,982,985],{"class":822,"line":823},[820,980,981],{"class":873},"tailscale",[820,983,984],{"class":841}," ip",[820,986,987],{"class":834}," -4\n",[989,990],"br",{},"The first line of ",[529,993,994],{},"tailscale status"," names this machine:",[811,997,999],{"className":813,"code":998,"language":815,"meta":816,"style":816},"tailscale status\n",[529,1000,1001],{"__ignoreMap":816},[820,1002,1003,1005],{"class":822,"line":823},[820,1004,981],{"class":873},[820,1006,1007],{"class":841}," status\n",[522,1009,1010,1011,1014,1015,1018,1019,1022],{},"Pause any active item. Once you edit ",[529,1012,1013],{},"bind"," in the next step, the ",[529,1016,1017],{},"kraft","\nCLI dials the new address, where nothing listens yet, so\n",[529,1020,1021],{},"kraft admin restart"," cannot list the agents it is about to end.",[522,1024,1025,1026,1028,1029,1031,1032,971,1034,1068,1070,1071,1073,1074,1077,1078,1080,1081,1084,1085,1087,1088,1091,1092,1094,1095,1097,1098,1100,1101,592,1103,532],{},"In ",[529,1027,322],{},", set ",[529,1030,1013],{}," to that address and add the machine's tailnet\nname to ",[529,1033,531],{},[811,1035,1040],{"className":1036,"code":1037,"filename":1038,"language":1039,"meta":816,"style":816},"language-yaml shiki shiki-themes github-light-high-contrast github-light-high-contrast github-dark-high-contrast","bind: 100.101.102.103\nallowed_hosts:\n  - mybox.tailnet-name.ts.net\n","config\u002Faccess.yaml","yaml",[529,1041,1042,1053,1060],{"__ignoreMap":816},[820,1043,1044,1047,1050],{"class":822,"line":823},[820,1045,1013],{"class":1046},"sb7M8",[820,1048,1049],{"class":826},": ",[820,1051,1052],{"class":834},"100.101.102.103\n",[820,1054,1055,1057],{"class":822,"line":900},[820,1056,531],{"class":1046},[820,1058,1059],{"class":826},":\n",[820,1061,1062,1065],{"class":822,"line":915},[820,1063,1064],{"class":826},"  - ",[820,1066,1067],{"class":841},"mybox.tailnet-name.ts.net\n",[989,1069],{},"Setting ",[529,1072,1013],{}," in the file, rather than passing ",[529,1075,1076],{},"--host",", keeps the ",[529,1079,1017],{},"\nCLI in your other shells pointed at the same address, and keeps the bind\nacross a restart. Run ",[529,1082,1083],{},"kraft admin doctor"," and read its ",[529,1086,322],{}," row to\nconfirm the file parses. Its ",[529,1089,1090],{},"server"," row fails until the restart.",[989,1093],{},"From here until the restart, change nothing on the Access screen. Opening\nit, or using its ",[753,1096,591],{}," button, is safe. A change made there\nrewrites ",[529,1099,322],{}," from what the running server holds, which reverts\nyour hand-edited ",[529,1102,1013],{},[529,1104,531],{},[522,1106,1107,1109],{},[568,1108,591],{"href":590}," so it reads the new bind.",[522,1111,1112,1113,1116],{},"From a device on your tailnet, open ",[529,1114,1115],{},"http:\u002F\u002Fmybox.tailnet-name.ts.net:8765\u002F",".\nTailscale encrypts the traffic between your devices.",[510,1118,1119,1120,1122,1123,1125],{},"After the restart the Access screen shows ",[753,1121,759],{}," as chosen, since the\nbind is off loopback. Do not click it: that writes ",[529,1124,655],{}," over your Tailscale\naddress.",[514,1127,646],{"id":1128},"on-your-local-network",[942,1130,1131,1143,1162,1172,1177],{},[522,1132,1133,1134,1136,1137,1139,1140,563],{},"Open Settings › Access and choose ",[753,1135,759],{}," (",[529,1138,655],{},"). The screen\nasks for what is missing: a password if none is set yet, and the name or\naddress your phone will type, filled in with this machine's LAN address\n(",[529,1141,1142],{},"192.168.1.20",[522,1144,1145,1146,1148,1149,1151,1152,699,1155,1157,1158,1161],{},"Click ",[753,1147,763],{},", which reads ",[753,1150,773],{}," when a password is already\nset. The bind, the password and the host are saved at\nonce, and the bind waits for a restart. The ",[753,1153,1154],{},"Allowed hosts",[753,1156,783],{},"\nand ",[753,1159,1160],{},"Sessions"," cards appear.",[522,1163,1164,1165,1167,1168,1171],{},"Under ",[753,1166,1154],{},", add any other name or address you will type in the\nphone's browser. The list is for the names other devices use: on the machine\nitself the board keeps working at ",[529,1169,1170],{},"http:\u002F\u002F127.0.0.1:8765",", behind the same\nsign-in. An empty list refuses every other device's browser, and the card\nthen offers this machine's address.",[522,1173,1174,1176],{},[568,1175,591],{"href":590}," so it binds the new address.",[522,1178,1179,1180,1183],{},"From the phone, open ",[529,1181,1182],{},"http:\u002F\u002F192.168.1.20:8765\u002F"," and log in. The traffic is\nplain HTTP, so anyone on the network can read it.",[514,1185,664],{"id":1186},"over-a-cloudflare-quick-tunnel",[1188,1189,1190,1197,1204],"warning",{},[510,1191,1192,1193,1196],{},"A Quick Tunnel puts the board on the public internet. Anyone who finds the\n",[529,1194,1195],{},"*.trycloudflare.com"," URL reaches the login page, and the password is the\nbarrier.",[510,1198,1199,1200,532],{},"Kraft locks an address out for 15 minutes after 5 failed logins, but\nif the tunnel does not pass on the visitor's address, every visitor counts as\none address and a stranger's guesses can lock you out too. See\n",[568,1201,1203],{"href":1202},"\u002Fproject\u002Fsecurity#login","Login",[510,1205,1206,1207,1210,1211,1214,1215,1217],{},"Open only the tunnel's ",[529,1208,1209],{},"https:\u002F\u002F"," URL, so the\nsession cookie is marked ",[529,1212,1213],{},"Secure",". The tunnel also needs a ",[529,1216,655],{}," bind,\nwhich listens on every interface, your LAN included. If your LAN is\nuntrusted, block the port at your firewall for other interfaces.",[942,1219,1220,1236,1249],{},[522,1221,1222,1223,1226,1227,1229,1230,1232,1233,1235],{},"Run ",[529,1224,1225],{},"cloudflared tunnel --url http:\u002F\u002Flocalhost:8765",". It prints a\n",[529,1228,1195],{}," URL. The URL changes every time ",[529,1231,672],{}," starts:\nafter the first time, add each new hostname under ",[753,1234,1154],{},", where it\napplies at once, with no restart.",[522,1237,1238,1239,1241,1242,1244,1245,539,1247,532],{},"On the Access screen, choose ",[753,1240,759],{},", setting the password if it\nasks. The phone's host field is pre-filled with the machine's LAN address:\nreplace it with the tunnel's hostname. Or, with a password already set, write\n",[529,1243,959],{}," and the hostname under ",[529,1246,531],{},[529,1248,322],{},[522,1250,1251,1176],{},[568,1252,591],{"href":590},[510,1254,1255,1256,1258,1259,1262,1263,1265,1266,1268,1269,1271,1272,1274,1275,699,1277,1280,1281,532],{},"Keep the bind in ",[529,1257,322],{},", not in ",[529,1260,1261],{},"kraft admin start --host 0.0.0.0",".\n",[529,1264,1021],{}," starts the server from ",[529,1267,322],{}," alone, so a bind you\npassed with ",[529,1270,1076],{}," is gone after a restart. The tunnel then reaches a server\non ",[529,1273,581],{},", which skips auth for local clients. Only the hostname check\nstands between it and the internet: Kraft refuses a request addressed to any name\nbut ",[529,1276,581],{},[529,1278,1279],{},"localhost"," or ",[529,1282,1283],{},"[::1]",[514,1285,684],{"id":1286},"behind-a-reverse-proxy-you-run",[510,1288,1289,1290,1293,1294,592,1296,1298],{},"Caddy, nginx or another proxy you run can serve the board at a name of your own\nwhile Kraft listens on a network bind behind it. Kraft listens on plain http, so\nthe proxy serves https. Off loopback, Kraft asks every client for the password or\na token before any API call, a proxy on this machine included. ",[529,1291,1292],{},"\u002Fapi\u002Fhealth",", the\npage and its assets are open. Kraft also checks the ",[529,1295,698],{},[529,1297,702],{}," the proxy\npasses on.",[942,1300,1301,1305,1369,1372,1551,1555],{},[522,1302,946,1303,532],{},[568,1304,741],{"href":949},[522,1306,1025,1307,1028,1309,1311,1312,971,1314,1341,1343,1344,1346,1347,1349,1350,1352,1353,1355,1356,1359,1360,1362,1363,1365,1366,1368],{},[529,1308,322],{},[529,1310,1013],{}," off loopback and add the name your browser will\ntype to ",[529,1313,531],{},[811,1315,1317],{"className":1036,"code":1316,"filename":1038,"language":1039,"meta":816,"style":816},"bind: 0.0.0.0\nallowed_hosts:\n  - kraft.example.com\n",[529,1318,1319,1328,1334],{"__ignoreMap":816},[820,1320,1321,1323,1325],{"class":822,"line":823},[820,1322,1013],{"class":1046},[820,1324,1049],{"class":826},[820,1326,1327],{"class":834},"0.0.0.0\n",[820,1329,1330,1332],{"class":822,"line":900},[820,1331,531],{"class":1046},[820,1333,1059],{"class":826},[820,1335,1336,1338],{"class":822,"line":915},[820,1337,1064],{"class":826},[820,1339,1340],{"class":841},"kraft.example.com\n",[989,1342],{},"Bind ",[529,1345,655],{},", not ",[529,1348,581],{},", even when the proxy runs on this machine. On a\nloopback bind Kraft ignores ",[529,1351,531],{}," and answers only a loopback ",[529,1354,698],{},".\nSo every request is refused unless the proxy sends ",[529,1357,1358],{},"Host: localhost",", and then\nthe board's sign-in and every change are refused as cross-site. That is why ",[568,1361,144],{"href":145},"\nserves webhooks and scripts only.",[989,1364],{},"Until the restart, change nothing on the Access screen: a change there\nrewrites ",[529,1367,322],{}," from what the running server holds and undoes this edit.",[522,1370,1371],{},"Block port 8765 at your firewall for every address but the proxy's, before you\nrestart. The wider bind listens on every network this machine is on, and a\nrequest that reaches the port directly meets only the password or a token, over\nplain http.",[522,1373,1374,1375,1530,1532,1533,1535,1536,1280,1538,1540,1541,1544,1545,532,1548,1550],{},"Set the proxy to pass what the table lists, with the setting your proxy uses\nfor each. The first four rows are what the board needs. The last one keeps the\nsign-in lockout per client.",[599,1376,1377,1390],{},[602,1378,1379],{},[605,1380,1381,1384,1387],{},[608,1382,1383],{},"The proxy must",[608,1385,1386],{},"What Kraft does with it",[608,1388,1389],{},"Without it",[618,1391,1392,1432,1466,1487,1510],{},[605,1393,1394,1403,1415],{},[623,1395,1396,1397,1399,1400,1402],{},"Pass ",[529,1398,698],{}," as the browser sent it, port included. Do not set it to ",[529,1401,1279],{}," or to Kraft's own address.",[623,1404,1405,1406,1408,1409,1411,1412,1414],{},"Checks the name against ",[529,1407,531],{}," for a browser request, and compares the ",[529,1410,698],{}," with the ",[529,1413,702],{}," of every write and of the live-update socket.",[623,1416,1417,1418,1420,1421,1423,1424,1280,1426,1428,1429,532],{},"An unlisted name gets a ",[529,1419,715],{}," (the page names it). A ",[529,1422,698],{}," rewritten to ",[529,1425,1279],{},[529,1427,581],{}," (nginx's default) loads the page, but Kraft refuses the sign-in, every change and the socket as ",[529,1430,1431],{},"cross-site request refused",[605,1433,1434,1439,1455],{},[623,1435,1396,1436,1438],{},[529,1437,702],{}," through unchanged.",[623,1440,1441,1442,1280,1445,1448,1449,1451,1452,1454],{},"Refuses a write (any request but ",[529,1443,1444],{},"GET",[529,1446,1447],{},"HEAD",") or a socket whose ",[529,1450,702],{}," names another host and port than ",[529,1453,698],{},", unless it names this machine.",[623,1456,1457,1458,1460,1461,699,1463,1465],{},"An ",[529,1459,702],{}," the proxy changes gets the ",[529,1462,715],{},[529,1464,1431],{},". One it drops turns the cross-site check off for writes.",[605,1467,1468,1474,1477],{},[623,1469,1470,1471,532],{},"Pass the WebSocket upgrade for ",[529,1472,1473],{},"\u002Fapi\u002Fws\u002Fevents",[623,1475,1476],{},"Applies the same checks and the sign-in to the socket, and closes it when one fails.",[623,1478,1479,1480,1483,1484,532],{},"No live updates: the sidebar shows ",[753,1481,1482],{},"reconnecting…"," instead of ",[753,1485,1486],{},"live",[605,1488,1489,1496,1505],{},[623,1490,1491,1492,1495],{},"Send ",[529,1493,1494],{},"X-Forwarded-Proto: https"," when it serves https.",[623,1497,1498,1499,1501,1502,532],{},"Marks the session cookie ",[529,1500,1213],{}," when the request is https or this header says ",[529,1503,1504],{},"https",[623,1506,1507,1508,532],{},"The cookie is not marked ",[529,1509,1213],{},[605,1511,1512,1518,1527],{},[623,1513,1514,1515,1517],{},"Append the client's address to ",[529,1516,725],{},". Do not pass a caller's own header through as sent.",[623,1519,1520,1521,1280,1523,1526],{},"Takes the client from the last address in the header that is not ",[529,1522,581],{},[529,1524,1525],{},"::1",", and counts failed logins per client.",[623,1528,1529],{},"Every visitor counts as one address: 5 failed logins from anyone lock everyone out for 15 minutes. A header passed through as sent lets a caller pick its own address, so it is never locked out.",[989,1531],{},"Kraft takes the client address from ",[529,1534,725],{}," only when the peer is at\n",[529,1537,581],{},[529,1539,1525],{},", which is uvicorn's default list. A proxy on another\nmachine connects from its own address, so Kraft takes every client for that\nproxy and the lockout is shared. ",[529,1542,1543],{},"FORWARDED_ALLOW_IPS"," in the server's\nenvironment replaces the list: set it to that proxy's address only, never ",[529,1546,1547],{},"*",[989,1549],{},"The hop from a proxy on another machine to Kraft is plain http, so the password\ncrosses that network in the clear.",[522,1552,1553,1176],{},[568,1554,591],{"href":590},[522,1556,1557,1558,1560],{},"Check it as ",[568,1559,596],{"href":595}," says, at the proxy's own name,\nincluding the two requests for this way.",[514,1562,591],{"id":1563},"restart-kraft",[510,1565,1566,1567,1571],{},"The first four ways end here, and so does ",[568,1568,1570],{"href":1569},"#rotate-the-token","Rotate the token",".\nKraft binds a new address, and writes a new token, only when it starts. Pick the\noption that matches how Kraft runs:",[519,1573,1574,1579,1587],{},[522,1575,1576,1577,532],{},"When Kraft runs as a service, the Access screen offers ",[753,1578,591],{},[522,1580,1581,1582,1584,1585,532],{},"Otherwise run ",[529,1583,1021],{},", which reads the new bind from\n",[529,1586,322],{},[522,1588,1589,1590,532],{},"A server running in a terminal only stops, so start it again there with\n",[529,1591,1017],{},[510,1593,1594,1595,1599,1600,532],{},"A restart ends the agent of every active item, and each stops as failed until\nyou retry it. The dialog says how many are active. Pause them first to avoid\nthat: see ",[568,1596,1598],{"href":1597},"\u002Fguides\u002Frun\u002Frestart-kraft#a-restart-ends-running-agents","A restart ends running agents",".\nWhen Kraft is back, resume what you paused with ",[529,1601,1602],{},"kraft item resume ID",[1604,1605,1607],"h3",{"id":1606},"if-kraft-does-not-come-back","If Kraft does not come back",[510,1609,1610,1611,1613,1614,699,1617,1619],{},"A restart stops the old server first, then starts one on the new bind. If\nTailscale is down or the address is mistyped, the start fails, and the ",[529,1612,1017],{},"\nCLI dials the new address, where nothing answers. For a server started with\n",[529,1615,1616],{},"--detach",[529,1618,1021],{}," prints the error and where the whole log is:",[811,1621,1626],{"className":1622,"code":1624,"language":1625,"meta":816},[1623],"language-text","kraft: detached start failed: \u003Cthe last error line of the log>\n\u003Cthe end of the server's output>\nkraft: the whole log is \u002Fhome\u002Fyou\u002F.kraft\u002Frun\u002Flogs\u002Fserver.log\n","text",[529,1627,1628,1632,1636],{"__ignoreMap":816},[820,1629,1631],{"className":1630},[822],"kraft: detached start failed: \u003Cthe last error line of the log>\n",[820,1633,1635],{"className":1634},[822],"\u003Cthe end of the server's output>\n",[820,1637,1639],{"className":1638},[822],"kraft: the whole log is \u002Fhome\u002Fyou\u002F.kraft\u002Frun\u002Flogs\u002Fserver.log\n",[510,1641,1642,1643,1646,1647,1649,1650,1653,1654,532],{},"The first line names the cause only when the log has a last line that looks\nlike ",[529,1644,1645],{},"SomeError: text",", and then it is that line. Otherwise the cause is in the\nend of the output. A server you ran in a terminal is only stopped: ",[529,1648,1021],{},"\nprints ",[529,1651,1652],{},"kraft: was running attached to a terminal - start it again there: kraft","\nand exits 1, and the error shows in that terminal when you run ",[529,1655,1017],{},[510,1657,1658,1659,1662,1663,532],{},"If the server does not answer within 10 seconds, it prints\n",[529,1660,1661],{},"kraft: detached start did not come up within 10s - check \u003Cthe log's path>",".\nA service is restarted through its manager instead: when the board stays\nunreachable, read the end of ",[529,1664,1665],{},"run\u002Flogs\u002Fserver.log",[942,1667,1668,1679],{},[522,1669,1670,1671,539,1673,1675,1676,1678],{},"Fix the cause, or put the old bind back: set ",[529,1672,1013],{},[529,1674,322],{}," to what\nit was before your edit (",[529,1677,581],{}," if you never changed it).",[522,1680,1681,1682,1684,1685,1687,1688,1690],{},"Start Kraft again: ",[529,1683,797],{},", or ",[529,1686,1021],{},"\nwhen it runs as a service, or ",[529,1689,1017],{}," in the terminal where you ran it.",[510,1692,1693,1694,1697,1698,1700,1701,532],{},"You know it worked when the ",[529,1695,1696],{},"status"," row of ",[529,1699,793],{}," says ",[529,1702,1703],{},"ok",[514,1705,596],{"id":1706},"check-it-worked",[510,1708,1709],{},"For the first four ways:",[942,1711,1712,1746,1752],{},[522,1713,1714,1715,1731,1733,1734,1737,1738,1741,1742,1745],{},"From the phone or other machine, request the health endpoint, which needs no\nlogin:",[811,1716,1718],{"className":813,"code":1717,"language":815,"meta":816,"style":816},"curl -s http:\u002F\u002Fmybox.tailnet-name.ts.net:8765\u002Fapi\u002Fhealth\n",[529,1719,1720],{"__ignoreMap":816},[820,1721,1722,1725,1728],{"class":822,"line":823},[820,1723,1724],{"class":873},"curl",[820,1726,1727],{"class":834}," -s",[820,1729,1730],{"class":841}," http:\u002F\u002Fmybox.tailnet-name.ts.net:8765\u002Fapi\u002Fhealth\n",[989,1732],{},"Replace the address with your way's: ",[529,1735,1736],{},"http:\u002F\u002F192.168.1.20:8765"," on a local\nnetwork, ",[529,1739,1740],{},"https:\u002F\u002F\u003Cyour-tunnel-hostname>"," through a Quick Tunnel,\n",[529,1743,1744],{},"https:\u002F\u002F\u003Cyour-proxy-name>"," behind a reverse proxy. A JSON\nstatus confirms the request reaches Kraft.",[522,1747,1748,1749,1751],{},"Open the same address without ",[529,1750,1292],{}," in a browser. You should see the\nlogin page. Log in with your password.",[522,1753,1754,1755,1757,1758,1761,1762,1764,1765,1767],{},"On a computer, the sidebar reads ",[753,1756,1486],{}," next to ",[753,1759,1760],{},"Kraft"," once the board's\nevent connection is open, and the board updates without a reload. If it stays\non ",[753,1763,1482],{},", check that anything between the browser and Kraft, such\nas a reverse proxy, passes WebSocket connections through and keeps the ",[529,1766,698],{},"\nheader the browser sent.",[510,1769,1770],{},"Behind a reverse proxy you run, also check that Kraft asks for credentials and\nthat the port is closed:",[942,1772,1774,1859],{"start":1773},4,[522,1775,1776,1777,971,1780,1820,1822,1823,1826,1827,1829,1830],{},"Request an API route with no credentials. Put your proxy's name in ",[529,1778,1779],{},"name",[811,1781,1783],{"className":813,"code":1782,"language":815,"meta":816,"style":816},"name=kraft.example.com\ncurl -s -o \u002Fdev\u002Fnull -w '%{http_code}\\n' \"https:\u002F\u002F$name\u002Fapi\u002Fwork-items\"\n",[529,1784,1785,1793],{"__ignoreMap":816},[820,1786,1787,1789,1791],{"class":822,"line":823},[820,1788,1779],{"class":826},[820,1790,831],{"class":830},[820,1792,1340],{"class":841},[820,1794,1795,1797,1799,1802,1805,1808,1811,1814,1817],{"class":822,"line":900},[820,1796,1724],{"class":873},[820,1798,1727],{"class":834},[820,1800,1801],{"class":834}," -o",[820,1803,1804],{"class":841}," \u002Fdev\u002Fnull",[820,1806,1807],{"class":834}," -w",[820,1809,1810],{"class":841}," '%{http_code}\\n'",[820,1812,1813],{"class":841}," \"https:\u002F\u002F",[820,1815,1816],{"class":826},"$name",[820,1818,1819],{"class":841},"\u002Fapi\u002Fwork-items\"\n",[989,1821],{},"It must print ",[529,1824,1825],{},"401",". A ",[529,1828,1825],{}," alone is not proof of this setup: signing in at\nstep 2 is. Any other answer means:",[519,1831,1832,1840,1852],{},[522,1833,1834,1836,1837,1839],{},[529,1835,715],{},": Kraft still binds ",[529,1838,581],{},", so restart it, or no password is set.",[522,1841,1842,1845,1846,1848,1849,1851],{},[529,1843,1844],{},"200",": Kraft took the request for a local one. It still binds ",[529,1847,581],{},",\nbehind a proxy that sends ",[529,1850,1358],{},". That is the webhook setup, not\nthis one.",[522,1853,1854,1855,1858],{},"Anything else comes from the proxy itself, such as a ",[529,1856,1857],{},"502"," when it cannot\nreach Kraft.",[522,1860,1861,1862,1865,1866,1899,1901],{},"From a machine other than the proxy's, request the health endpoint at Kraft's\nown port. Set ",[529,1863,1864],{},"machine"," to this machine's address before you run it:",[811,1867,1869],{"className":813,"code":1868,"language":815,"meta":816,"style":816},"machine=192.168.1.20\ncurl -m 5 \"http:\u002F\u002F$machine:8765\u002Fapi\u002Fhealth\"\n",[529,1870,1871,1880],{"__ignoreMap":816},[820,1872,1873,1875,1877],{"class":822,"line":823},[820,1874,1864],{"class":826},[820,1876,831],{"class":830},[820,1878,1879],{"class":841},"192.168.1.20\n",[820,1881,1882,1884,1887,1890,1893,1896],{"class":822,"line":900},[820,1883,1724],{"class":873},[820,1885,1886],{"class":834}," -m",[820,1888,1889],{"class":834}," 5",[820,1891,1892],{"class":841}," \"http:\u002F\u002F",[820,1894,1895],{"class":826},"$machine",[820,1897,1898],{"class":841},":8765\u002Fapi\u002Fhealth\"\n",[989,1900],{},"With the port blocked, this must fail: it times out, or is refused. A JSON\nstatus means the port is still open to the sign-in over plain http: block it\nbefore you go on.",[510,1903,1904,1905,532],{},"The webhook proxy way has its own check, at the end of ",[568,1906,1908],{"href":1907},"\u002Fguides\u002Frun\u002Fput-a-proxy-in-front-of-kraft#check-it-worked","its page",[1604,1910,1912],{"id":1911},"the-browser-says-kraft-does-not-answer-to-the-name-you-opened","The browser says Kraft does not answer to the name you opened",[510,1914,1915,1916,1918],{},"The hostname is missing from ",[529,1917,531],{},". The page names it.",[519,1920,1921,1930,1936],{},[522,1922,1923,1924,1926,1927,1929],{},"The list is held to browsers only: ",[529,1925,1724],{},", the ",[529,1928,1017],{}," CLI and MCP are not\nchecked against it.",[522,1931,1932,1933,1935],{},"Add the name in ",[529,1934,322],{}," and restart, or on the Access screen from an\naddress already on the list, where it applies at once.",[522,1937,1938,1939,1942,1943,1946],{},"Enter the name alone, as ",[529,1940,1941],{},"mybox.tailnet-name.ts.net",". Kraft drops a port or an\n",[529,1944,1945],{},"http:\u002F\u002F"," you type with it, and refuses a wildcard.",[514,1948,1570],{"id":1949},"rotate-the-token",[510,1951,1952,592,1955,1958,1959,1962,1963,1965,1966,1970],{},[529,1953,1954],{},"$KRAFT_HOME\u002Frun\u002Fmcp-token",[529,1956,1957],{},"$KRAFT_HOME\u002Frun\u002Ftrigger-token"," stay the same\nuntil you delete them. The commands below follow ",[529,1960,1961],{},"KRAFT_RUN_DIR"," when it is\nset, and ",[529,1964,1083],{}," prints each token's path. Rotate one when a copy\nhas leaked, or when someone who held it should no longer have it. ",[568,1967,1969],{"href":1968},"\u002Fproject\u002Fsecurity#the-bearer-token","The bearer token","\nsays what each one grants. A server accepts the old value until it restarts.",[942,1972,1973,1986,2069,2077,2082],{},[522,1974,1975,1976,1979,1980,1982,1983,1985],{},"Pause any active item. A restart ends their agents, and once the\n",[529,1977,1978],{},"mcp-token"," is gone a server bound off loopback refuses the ",[529,1981,1017],{}," CLI, so\n",[529,1984,1021],{}," cannot list them.",[522,1987,1988,1989],{},"Delete the file you are rotating, or both. Run only the lines you need:",[811,1990,1992],{"className":813,"code":1991,"language":815,"meta":816,"style":816},"rm \"${KRAFT_RUN_DIR:-${KRAFT_HOME:-$HOME\u002F.kraft}\u002Frun}\u002Ftrigger-token\"\nrm \"${KRAFT_RUN_DIR:-${KRAFT_HOME:-$HOME\u002F.kraft}\u002Frun}\u002Fmcp-token\"\n",[529,1993,1994,2036],{"__ignoreMap":816},[820,1995,1996,1999,2002,2004,2007,2010,2013,2015,2018,2021,2023,2025,2028,2030,2033],{"class":822,"line":823},[820,1997,1998],{"class":873},"rm",[820,2000,2001],{"class":841}," \"${",[820,2003,1961],{"class":826},[820,2005,2006],{"class":830},":-",[820,2008,2009],{"class":841},"${",[820,2011,2012],{"class":826},"KRAFT_HOME",[820,2014,2006],{"class":830},[820,2016,2017],{"class":826},"$HOME",[820,2019,2020],{"class":830},"\u002F",[820,2022,532],{"class":841},[820,2024,1017],{"class":826},[820,2026,2027],{"class":841},"}",[820,2029,2020],{"class":830},[820,2031,2032],{"class":826},"run",[820,2034,2035],{"class":841},"}\u002Ftrigger-token\"\n",[820,2037,2038,2040,2042,2044,2046,2048,2050,2052,2054,2056,2058,2060,2062,2064,2066],{"class":822,"line":900},[820,2039,1998],{"class":873},[820,2041,2001],{"class":841},[820,2043,1961],{"class":826},[820,2045,2006],{"class":830},[820,2047,2009],{"class":841},[820,2049,2012],{"class":826},[820,2051,2006],{"class":830},[820,2053,2017],{"class":826},[820,2055,2020],{"class":830},[820,2057,532],{"class":841},[820,2059,1017],{"class":826},[820,2061,2027],{"class":841},[820,2063,2020],{"class":830},[820,2065,2032],{"class":826},[820,2067,2068],{"class":841},"}\u002Fmcp-token\"\n",[522,2070,2071,2073,2074,532],{},[568,2072,591],{"href":590},". Kraft writes a new token on start, with mode\n",[529,2075,2076],{},"0600",[522,2078,2079,2080,532],{},"Resume the items you paused: ",[529,2081,1602],{},[522,2083,2084,2085,2088,2089,2091,2092,2094],{},"Put the new value wherever you keep a copy. A CI secret or a webhook sender\nholds the ",[529,2086,2087],{},"trigger-token",". A script, or a client on another machine, holds the\n",[529,2090,1978],{},". The ",[529,2093,1017],{}," CLI and the MCP server on this machine read the file\non every call, so they need no setup.",[510,2096,2097],{},"You know it worked when the file's modification time is the time of the restart:",[811,2099,2101],{"className":813,"code":2100,"language":815,"meta":816,"style":816},"ls -l \"${KRAFT_RUN_DIR:-${KRAFT_HOME:-$HOME\u002F.kraft}\u002Frun}\u002Ftrigger-token\"\nls -l \"${KRAFT_RUN_DIR:-${KRAFT_HOME:-$HOME\u002F.kraft}\u002Frun}\u002Fmcp-token\"\n",[529,2102,2103,2139],{"__ignoreMap":816},[820,2104,2105,2108,2111,2113,2115,2117,2119,2121,2123,2125,2127,2129,2131,2133,2135,2137],{"class":822,"line":823},[820,2106,2107],{"class":873},"ls",[820,2109,2110],{"class":834}," -l",[820,2112,2001],{"class":841},[820,2114,1961],{"class":826},[820,2116,2006],{"class":830},[820,2118,2009],{"class":841},[820,2120,2012],{"class":826},[820,2122,2006],{"class":830},[820,2124,2017],{"class":826},[820,2126,2020],{"class":830},[820,2128,532],{"class":841},[820,2130,1017],{"class":826},[820,2132,2027],{"class":841},[820,2134,2020],{"class":830},[820,2136,2032],{"class":826},[820,2138,2035],{"class":841},[820,2140,2141,2143,2145,2147,2149,2151,2153,2155,2157,2159,2161,2163,2165,2167,2169,2171],{"class":822,"line":900},[820,2142,2107],{"class":873},[820,2144,2110],{"class":834},[820,2146,2001],{"class":841},[820,2148,1961],{"class":826},[820,2150,2006],{"class":830},[820,2152,2009],{"class":841},[820,2154,2012],{"class":826},[820,2156,2006],{"class":830},[820,2158,2017],{"class":826},[820,2160,2020],{"class":830},[820,2162,532],{"class":841},[820,2164,1017],{"class":826},[820,2166,2027],{"class":841},[820,2168,2020],{"class":830},[820,2170,2032],{"class":826},[820,2172,2068],{"class":841},[510,2174,2175,2176,2178,2179,592,2182,2185,2186,532],{},"A file you failed to delete keeps its old time. ",[529,2177,1083],{}," also shows\nthe ",[529,2180,2181],{},"mcp token",[529,2183,2184],{},"trigger token"," rows with the file's path and mode ",[529,2187,2076],{},[514,2189,2191],{"id":2190},"next-steps","Next steps",[519,2193,2194,2199,2204,2209],{},[522,2195,2196,2198],{},[568,2197,88],{"href":89},": the phone layout you now reach",[522,2200,2201,2203],{},[568,2202,477],{"href":478},": the threat model behind the password and the host check",[522,2205,2206,2208],{},[568,2207,424],{"href":425},": call the API from off-machine",[522,2210,2211,2213,2214],{},[568,2212,322],{"href":323},": every field of ",[529,2215,322],{},[2217,2218,2219],"style",{},"html pre.shiki code .s7iLA, html code.shiki .s7iLA{--shiki-light:#0E1116;--shiki-default:#0E1116;--shiki-dark:#F0F3F6}html pre.shiki code .sklAV, html code.shiki .sklAV{--shiki-light:#A0111F;--shiki-default:#A0111F;--shiki-dark:#FF9492}html pre.shiki code .ssYy9, html code.shiki .ssYy9{--shiki-light:#023B95;--shiki-default:#023B95;--shiki-dark:#91CBFF}html pre.shiki code .semJd, html code.shiki .semJd{--shiki-light:#032563;--shiki-default:#032563;--shiki-dark:#ADDCFF}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);}html pre.shiki code .szw1H, html code.shiki .szw1H{--shiki-light:#702C00;--shiki-default:#702C00;--shiki-dark:#FFB757}html pre.shiki code .sb7M8, html code.shiki .sb7M8{--shiki-light:#024C1A;--shiki-default:#024C1A;--shiki-dark:#72F088}",{"title":816,"searchDepth":900,"depth":900,"links":2221},[2222,2223,2224,2225,2226,2227,2228,2229,2232,2235,2236],{"id":516,"depth":900,"text":517},{"id":575,"depth":900,"text":571},{"id":740,"depth":900,"text":741},{"id":929,"depth":900,"text":628},{"id":1128,"depth":900,"text":646},{"id":1186,"depth":900,"text":664},{"id":1286,"depth":900,"text":684},{"id":1563,"depth":900,"text":591,"children":2230},[2231],{"id":1606,"depth":915,"text":1607},{"id":1706,"depth":900,"text":596,"children":2233},[2234],{"id":1911,"depth":915,"text":1912},{"id":1949,"depth":900,"text":1570},{"id":2190,"depth":900,"text":2191},"Approve or reject a gate from a phone, over Tailscale, a tunnel or a reverse proxy you run, using the same password auth as the local board, get back if Kraft does not restart, and rotate the token.","md",null,{},true,{"title":140,"description":2237},"gaTDSdv7Tb2Asj3pfGRV8jeRKwoK-zaf_OFKA0mEfzA",[2245,2247],{"title":131,"path":132,"stem":133,"description":2246,"children":-1},"Give the agent CLI a worker runs on, whether Claude Code, Codex, Cursor, OpenCode, Amp, Antigravity or Gemini CLI, a login it can use headless, and check that the worker reaches it.",{"title":144,"path":145,"stem":146,"description":2248,"children":-1},"Let a tunnel or reverse proxy on this machine pass webhooks and scripts to a loopback-bound Kraft by sending Host localhost, and check that nobody gets in without signing in.",1791801240796]