[{"data":1,"prerenderedAt":442},["ShallowReactive",2],{"docs-navigation":3,"docs-\u002Fdocs\u002Fget-started\u002Fmaintenance":90,"docs-surround-\u002Fdocs\u002Fget-started\u002Fmaintenance":437},[4],{"title":5,"path":6,"stem":7,"children":8,"page":34},"Docs","\u002Fdocs","docs",[9,35,56,77],{"title":10,"path":11,"stem":12,"children":13,"page":34},"Get Started","\u002Fdocs\u002Fget-started","docs\u002F1.get-started",[14,18,22,26,30],{"title":15,"path":16,"stem":17},"Introduction","\u002Fdocs\u002Fget-started\u002Fintroduction","docs\u002F1.get-started\u002F1.introduction",{"title":19,"path":20,"stem":21},"Concepts","\u002Fdocs\u002Fget-started\u002Fconcepts","docs\u002F1.get-started\u002F2.concepts",{"title":23,"path":24,"stem":25},"Installation","\u002Fdocs\u002Fget-started\u002Finstallation","docs\u002F1.get-started\u002F3.installation",{"title":27,"path":28,"stem":29},"Setup","\u002Fdocs\u002Fget-started\u002Fsetup","docs\u002F1.get-started\u002F4.setup",{"title":31,"path":32,"stem":33},"Maintenance","\u002Fdocs\u002Fget-started\u002Fmaintenance","docs\u002F1.get-started\u002F5.maintenance",false,{"title":36,"path":37,"stem":38,"children":39,"page":34},"Usage","\u002Fdocs\u002Fusage","docs\u002F2.usage",[40,44,48,52],{"title":41,"path":42,"stem":43},"Projects","\u002Fdocs\u002Fusage\u002Fprojects","docs\u002F2.usage\u002F1.projects",{"title":45,"path":46,"stem":47},"Workflows","\u002Fdocs\u002Fusage\u002Fworkflows","docs\u002F2.usage\u002F2.workflows",{"title":49,"path":50,"stem":51},"Triggers","\u002Fdocs\u002Fusage\u002Ftriggers","docs\u002F2.usage\u002F3.triggers",{"title":53,"path":54,"stem":55},"AI Agent","\u002Fdocs\u002Fusage\u002Fagent","docs\u002F2.usage\u002F4.agent",{"title":57,"path":58,"stem":59,"children":60,"page":34},"Integrations","\u002Fdocs\u002Fintegrations","docs\u002F3.integrations",[61,65,69,73],{"title":62,"path":63,"stem":64},"GitHub","\u002Fdocs\u002Fintegrations\u002Fgithub","docs\u002F3.integrations\u002F1.github",{"title":66,"path":67,"stem":68},"Jira","\u002Fdocs\u002Fintegrations\u002Fjira","docs\u002F3.integrations\u002F2.jira",{"title":70,"path":71,"stem":72},"Plane","\u002Fdocs\u002Fintegrations\u002Fplane","docs\u002F3.integrations\u002F3.plane",{"title":74,"path":75,"stem":76},"Linear","\u002Fdocs\u002Fintegrations\u002Flinear","docs\u002F3.integrations\u002F4.linear",{"title":78,"path":79,"stem":80,"children":81,"page":34},"Resources","\u002Fdocs\u002Fresources","docs\u002F4.resources",[82,86],{"title":83,"path":84,"stem":85},"Beta Testers","\u002Fdocs\u002Fresources\u002Fbeta-testers","docs\u002F4.resources\u002F1.beta-testers",{"title":87,"path":88,"stem":89},"Troubleshooting","\u002Fdocs\u002Fresources\u002Ftroubleshooting","docs\u002F4.resources\u002F2.troubleshooting",{"id":91,"title":31,"body":92,"description":431,"extension":432,"meta":433,"navigation":434,"path":32,"seo":435,"stem":33,"__hash__":436},"docs_en\u002Fdocs\u002F1.get-started\u002F5.maintenance.md",{"type":93,"value":94,"toc":421},"minimark",[95,99,104,112,117,120,220,224,231,235,246,271,274,278,289,329,332,336,347,365,371,378,382,385,388,417],[96,97,98],"p",{},"A self-hosted instance needs three things from its operator: updates, a backup, and an eye on certificates. All of it happens on the server, on the System page of the dashboard, or under Settings, Advanced. Managed beta instances are maintained by us, so this page only applies to self-hosted installs.",[100,101,103],"h2",{"id":102},"updating","Updating",[96,105,106,107,111],{},"Releases are git tags in the form ",[108,109,110],"code",{},"vX.Y.Z",", built by CI into a Docker image. When a newer release exists, the System page shows its release notes and an update button. Automatic updates are set under Settings, Advanced.",[113,114,116],"h3",{"id":115},"manual-updates","Manual Updates",[96,118,119],{},"The System page shows an \"Update to vX.Y.Z\" button. It swaps the app to the new version with all data intact and takes about a minute, during which the dashboard is unreachable. Only the owner can start it, because it changes the running code for every member.",[121,122,123,126],"note",{},[96,124,125],{},"The manual equivalent on the server, for example when the dashboard is down:",[127,128,133],"pre",{"className":129,"code":130,"language":131,"meta":132,"style":132},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","cd \u002Fopt\u002Fknecht\ngit fetch --tags && git checkout vX.Y.Z\nsed -i 's\u002F^KNECHT_VERSION=.*\u002FKNECHT_VERSION=vX.Y.Z\u002F' .env\ndocker compose pull && docker compose up -d\n","bash","",[108,134,135,148,174,195],{"__ignoreMap":132},[136,137,140,144],"span",{"class":138,"line":139},"line",1,[136,141,143],{"class":142},"s2Zo4","cd",[136,145,147],{"class":146},"sfazB"," \u002Fopt\u002Fknecht\n",[136,149,151,155,158,161,165,168,171],{"class":138,"line":150},2,[136,152,154],{"class":153},"sBMFI","git",[136,156,157],{"class":146}," fetch",[136,159,160],{"class":146}," --tags",[136,162,164],{"class":163},"sMK4o"," &&",[136,166,167],{"class":153}," git",[136,169,170],{"class":146}," checkout",[136,172,173],{"class":146}," vX.Y.Z\n",[136,175,177,180,183,186,189,192],{"class":138,"line":176},3,[136,178,179],{"class":153},"sed",[136,181,182],{"class":146}," -i",[136,184,185],{"class":163}," '",[136,187,188],{"class":146},"s\u002F^KNECHT_VERSION=.*\u002FKNECHT_VERSION=vX.Y.Z\u002F",[136,190,191],{"class":163},"'",[136,193,194],{"class":146}," .env\n",[136,196,198,201,204,207,209,212,214,217],{"class":138,"line":197},4,[136,199,200],{"class":153},"docker",[136,202,203],{"class":146}," compose",[136,205,206],{"class":146}," pull",[136,208,164],{"class":163},[136,210,211],{"class":153}," docker",[136,213,203],{"class":146},[136,215,216],{"class":146}," up",[136,218,219],{"class":146}," -d\n",[113,221,223],{"id":222},"automatic-updates","Automatic Updates",[96,225,226,227,230],{},"Under Settings, Advanced, the panel \"Automatic updates\" has a field for a cron expression in server time, for example ",[108,228,229],{},"0 3 * * *"," for nightly at 03:00. Once set, Knecht updates itself as soon as a new release exists and no run is active. Leave the field empty to update by hand.",[113,232,234],{"id":233},"host-level-updates","Host-Level Updates",[96,236,237,238,245],{},"The in-app update covers the app only. Docker, the ",[239,240,244],"a",{"href":241,"rel":242},"https:\u002F\u002Fddev.com",[243],"nofollow","DDEV"," CLI, and the DDEV image warm-up live on the host and are not touched. When a release needs a newer DDEV or a changed host setup, the release notes say so, and the provisioning script has to be re-run once:",[127,247,249],{"className":129,"code":248,"language":131,"meta":132,"style":132},"sudo KNECHT_UID=1000 KNECHT_GID=1000 \u002Fopt\u002Fknecht\u002Fscripts\u002Fprovision-host.sh\n",[108,250,251],{"__ignoreMap":132},[136,252,253,256,259,263,266,268],{"class":138,"line":139},[136,254,255],{"class":153},"sudo",[136,257,258],{"class":146}," KNECHT_UID=",[136,260,262],{"class":261},"sbssI","1000",[136,264,265],{"class":146}," KNECHT_GID=",[136,267,262],{"class":261},[136,269,270],{"class":146}," \u002Fopt\u002Fknecht\u002Fscripts\u002Fprovision-host.sh\n",[96,272,273],{},"The script is idempotent and safe to run at any time.",[113,275,277],{"id":276},"pre-releases","Pre-Releases",[96,279,280,281,284,285,288],{},"Tags with a hyphen, such as ",[108,282,283],{},"v0.3.0-rc.1",", are pre-releases. CI builds them like any release, but they are never offered as an update and a normal install ignores them. To test one, fetch the installer from that tag and pin the same tag with ",[108,286,287],{},"KNECHT_REF",", so installer and version cannot diverge:",[127,290,292],{"className":129,"code":291,"language":131,"meta":132,"style":132},"curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fknecht-works\u002Fknecht-cloud\u002Fv0.3.0-rc.1\u002Fscripts\u002Finstall.sh \\\n  | sudo env KNECHT_DOMAIN=knecht.example.com KNECHT_REF=v0.3.0-rc.1 bash\n",[108,293,294,309],{"__ignoreMap":132},[136,295,296,299,302,305],{"class":138,"line":139},[136,297,298],{"class":153},"curl",[136,300,301],{"class":146}," -fsSL",[136,303,304],{"class":146}," https:\u002F\u002Fraw.githubusercontent.com\u002Fknecht-works\u002Fknecht-cloud\u002Fv0.3.0-rc.1\u002Fscripts\u002Finstall.sh",[136,306,308],{"class":307},"sTEyZ"," \\\n",[136,310,311,314,317,320,323,326],{"class":138,"line":150},[136,312,313],{"class":163},"  |",[136,315,316],{"class":153}," sudo",[136,318,319],{"class":146}," env",[136,321,322],{"class":146}," KNECHT_DOMAIN=knecht.example.com",[136,324,325],{"class":146}," KNECHT_REF=v0.3.0-rc.1",[136,327,328],{"class":146}," bash\n",[96,330,331],{},"Once the matching stable release is published, the instance offers it as a regular update. Updating from a stable version to a pre-release is not possible.",[100,333,335],{"id":334},"backup-and-rollback","Backup and Rollback",[96,337,338,339,342,343,346],{},"All state lives in ",[108,340,341],{},"\u002Fdata\u002Fknecht\u002Fdata",": the SQLite database, run archives, and uploaded database dumps. Back that folder up, or snapshot the whole server. Project checkouts under ",[108,344,345],{},"\u002Fdata\u002Fknecht\u002Fprojects"," are disposable, Knecht clones them again when needed.",[348,349,350],"warning",{},[96,351,352,353,356,357,360,361,364],{},"Stored secrets, such as the GitHub App credentials, the AI key, and the tokens of connected integrations, are encrypted with a key derived from ",[108,354,355],{},"NUXT_SESSION_PASSWORD"," in ",[108,358,359],{},"\u002Fopt\u002Fknecht\u002F.env",". A backup of the data folder alone cannot be restored without that file. Keep a copy of the ",[108,362,363],{},".env"," as well, ideally separate from the data backup.",[96,366,367,368,370],{},"Database migrations run forward only. Checking out an older release does not roll the schema back. Take a copy of ",[108,369,341],{}," before an update if you want a safe way back, and restore the copy together with the older tag.",[96,372,373,374,377],{},"On a Mac, both folders live inside the Lima VM. Reach them through ",[108,375,376],{},"limactl shell knecht",", or back up the VM disk as a whole.",[100,379,381],{"id":380},"certificates","Certificates",[96,383,384],{},"Caddy handles TLS on its own. It fetches the certificate for the dashboard on first start and one certificate per preview hostname on demand, so the first visit of a new preview URL takes a few extra seconds. Nothing needs renewing by hand.",[96,386,387],{},"Let's Encrypt issues at most 50 new certificates per week per domain. Each newly visited preview hostname uses one, renewals do not. A team with many sessions per week can hit that limit. The way out is a wildcard certificate for the preview zone:",[389,390,391,399,402],"ol",{},[392,393,394,395,398],"li",{},"Delegate the preview subzone to a DNS provider with an API, for example ",[108,396,397],{},"preview.knecht.example.com NS -> Hetzner DNS",". The main zone stays where it is.",[392,400,401],{},"Build Caddy with the matching DNS plugin.",[392,403,404,405,408,409,412,413,416],{},"In ",[108,406,407],{},"\u002Fopt\u002Fknecht\u002FCaddyfile",", replace ",[108,410,411],{},"on_demand"," with ",[108,414,415],{},"tls { dns \u003Cprovider> }",".",[418,419,420],"style",{},"html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":132,"searchDepth":150,"depth":150,"links":422},[423,429,430],{"id":102,"depth":150,"text":103,"children":424},[425,426,427,428],{"id":115,"depth":176,"text":116},{"id":222,"depth":176,"text":223},{"id":233,"depth":176,"text":234},{"id":276,"depth":176,"text":277},{"id":334,"depth":150,"text":335},{"id":380,"depth":150,"text":381},"Keep a self-hosted instance up to date and backed up.","md",{},true,{"title":31,"description":431},"qaduP-UbieDni3M97HO-cF09AdGkPl3iph4gFMlhtog",[438,440],{"title":27,"path":28,"stem":29,"description":439,"children":-1},"Configure your Knecht instance after installation.",{"title":41,"path":42,"stem":43,"description":441,"children":-1},"Add a project, run it through Knecht, and manage it afterward.",1790265015950]