[{"data":1,"prerenderedAt":689},["ShallowReactive",2],{"navigation_docs":3,"-docs-deploy-deploy-hooks":130,"-docs-deploy-deploy-hooks-surround":684},[4,25,70,90,115],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting started",false,"\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F1.getting-started\u002F2.installation","i-lucide-terminal",{"title":21,"path":22,"stem":23,"icon":24},"Quickstart","\u002Fdocs\u002Fgetting-started\u002Fquickstart","docs\u002F1.getting-started\u002F3.quickstart","i-lucide-rocket",{"title":26,"icon":6,"path":27,"stem":28,"children":29,"page":6},"Deploy","\u002Fdocs\u002Fdeploy","docs\u002F2.deploy",[30,35,40,45,50,55,60,65],{"title":31,"path":32,"stem":33,"icon":34},"Projects and services","\u002Fdocs\u002Fdeploy\u002Fprojects-and-services","docs\u002F2.deploy\u002F1.projects-and-services","i-lucide-folder-kanban",{"title":36,"path":37,"stem":38,"icon":39},"Docker images","\u002Fdocs\u002Fdeploy\u002Fdocker-images","docs\u002F2.deploy\u002F2.docker-images","i-lucide-container",{"title":41,"path":42,"stem":43,"icon":44},"Git repositories","\u002Fdocs\u002Fdeploy\u002Fgit-repositories","docs\u002F2.deploy\u002F3.git-repositories","i-lucide-git-branch",{"title":46,"path":47,"stem":48,"icon":49},"Databases","\u002Fdocs\u002Fdeploy\u002Fdatabases","docs\u002F2.deploy\u002F4.databases","i-lucide-database",{"title":51,"path":52,"stem":53,"icon":54},"Environment variables","\u002Fdocs\u002Fdeploy\u002Fenvironment-variables","docs\u002F2.deploy\u002F5.environment-variables","i-lucide-key-round",{"title":56,"path":57,"stem":58,"icon":59},"Deployments and logs","\u002Fdocs\u002Fdeploy\u002Fdeployments","docs\u002F2.deploy\u002F6.deployments","i-lucide-scroll-text",{"title":61,"path":62,"stem":63,"icon":64},"Deploy hooks","\u002Fdocs\u002Fdeploy\u002Fdeploy-hooks","docs\u002F2.deploy\u002F7.deploy-hooks","i-lucide-webhook",{"title":66,"path":67,"stem":68,"icon":69},"Domains and HTTPS","\u002Fdocs\u002Fdeploy\u002Fdomains","docs\u002F2.deploy\u002F8.domains","i-lucide-lock",{"title":71,"icon":6,"path":72,"stem":73,"children":74,"page":6},"Backups","\u002Fdocs\u002Fbackups","docs\u002F3.backups",[75,80,85],{"title":76,"path":77,"stem":78,"icon":79},"Backup destinations","\u002Fdocs\u002Fbackups\u002Fbackup-destinations","docs\u002F3.backups\u002F1.backup-destinations","i-lucide-hard-drive-upload",{"title":81,"path":82,"stem":83,"icon":84},"Database backups","\u002Fdocs\u002Fbackups\u002Fdatabase-backups","docs\u002F3.backups\u002F2.database-backups","i-lucide-archive-restore",{"title":86,"path":87,"stem":88,"icon":89},"Backing up Harblet","\u002Fdocs\u002Fbackups\u002Fharblet-backups","docs\u002F3.backups\u002F3.harblet-backups","i-lucide-shield-check",{"title":91,"icon":6,"path":92,"stem":93,"children":94,"page":6},"Administration","\u002Fdocs\u002Fadministration","docs\u002F4.administration",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Harblet's domain","\u002Fdocs\u002Fadministration\u002Fharblet-domain","docs\u002F4.administration\u002F1.harblet-domain","i-lucide-globe",{"title":101,"path":102,"stem":103,"icon":104},"Servers","\u002Fdocs\u002Fadministration\u002Fservers","docs\u002F4.administration\u002F2.servers","i-lucide-server",{"title":106,"path":107,"stem":108,"icon":109},"Team and account","\u002Fdocs\u002Fadministration\u002Fteam","docs\u002F4.administration\u002F3.team","i-lucide-users",{"title":111,"path":112,"stem":113,"icon":114},"Updates","\u002Fdocs\u002Fadministration\u002Fupdates","docs\u002F4.administration\u002F4.updates","i-lucide-refresh-cw",{"title":116,"icon":6,"path":117,"stem":118,"children":119,"page":6},"Reference","\u002Fdocs\u002Freference","docs\u002F5.reference",[120,125],{"title":121,"path":122,"stem":123,"icon":124},"Troubleshooting","\u002Fdocs\u002Freference\u002Ftroubleshooting","docs\u002F5.reference\u002F1.troubleshooting","i-lucide-life-buoy",{"title":126,"path":127,"stem":128,"icon":129},"License","\u002Fdocs\u002Freference\u002Flicense","docs\u002F5.reference\u002F2.license","i-lucide-scale",{"id":131,"title":61,"body":132,"description":677,"extension":678,"links":679,"meta":680,"navigation":681,"path":62,"seo":682,"stem":63,"__hash__":683},"docs\u002Fdocs\u002F2.deploy\u002F7.deploy-hooks.md",{"type":133,"value":134,"toc":670},"minimark",[135,152,170,173,178,189,220,224,228,474,478,558,564,614,628,632,638,644,648,658,666],[136,137,138,139,143,144,148,149,151],"p",{},"Every image and Git service has a secret ",[140,141,142],"strong",{},"deploy hook"," URL. A ",[145,146,147],"code",{},"POST"," request to it deploys the service, just like the ",[140,150,26],{}," button. Call it at the end of your CI pipeline, after tests and linting pass.",[153,154,155,163],"ul",{},[156,157,158,159,162],"li",{},"A ",[140,160,161],{},"Git service"," builds the newest commit of its branch.",[156,164,165,166,169],{},"An ",[140,167,168],{},"image service"," pulls its tag again. Push the new image under the same tag first.",[136,171,172],{},"The hook deploys the service's saved settings and environment variables, including changes that haven't been deployed yet.",[174,175,177],"h2",{"id":176},"get-the-url","Get the URL",[136,179,180,181,184,185,188],{},"Open the service's ",[140,182,183],{},"Settings"," tab. The ",[140,186,187],{},"Deploy hook"," card shows the URL and a ready-made command:",[190,191,196],"pre",{"className":192,"code":193,"language":194,"meta":195,"style":195},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl --fail -X POST https:\u002F\u002Fharblet.example.com\u002Fapi\u002Fhooks\u002F2f1c9e4a-7b3d-4e8f-9a61-0c5d8e7f3b12\n","bash","",[145,197,198],{"__ignoreMap":195},[199,200,203,207,211,214,217],"span",{"class":201,"line":202},"line",1,[199,204,206],{"class":205},"sBMFI","curl",[199,208,210],{"class":209},"sfazB"," --fail",[199,212,213],{"class":209}," -X",[199,215,216],{"class":209}," POST",[199,218,219],{"class":209}," https:\u002F\u002Fharblet.example.com\u002Fapi\u002Fhooks\u002F2f1c9e4a-7b3d-4e8f-9a61-0c5d8e7f3b12\n",[221,222,223],"warning",{},"Anyone with the URL can deploy the service. Store it as a secret in your CI system, not in your repository.",[174,225,227],{"id":226},"call-it-from-your-pipeline","Call it from your pipeline",[229,230,231,397],"tabs",{},[232,233,236,243],"tabs-item",{"icon":234,"label":235},"i-simple-icons-githubactions","GitHub Actions",[136,237,238,239,242],{},"Add the URL as a repository secret named ",[145,240,241],{},"HARBLET_DEPLOY_HOOK",", then add a step at the end of your workflow:",[190,244,249],{"className":245,"code":246,"filename":247,"language":248,"meta":195,"style":195},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","name: Deploy\n\non:\n  push:\n    branches: [main]\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - run: npm ci && npm test\n      - name: Deploy to Harblet\n        run: curl --fail -X POST \"${{ secrets.HARBLET_DEPLOY_HOOK }}\"\n",".github\u002Fworkflows\u002Fdeploy.yml","yaml",[145,250,251,264,271,281,289,306,311,319,327,338,346,360,373,386],{"__ignoreMap":195},[199,252,253,257,261],{"class":201,"line":202},[199,254,256],{"class":255},"swJcz","name",[199,258,260],{"class":259},"sMK4o",":",[199,262,263],{"class":209}," Deploy\n",[199,265,267],{"class":201,"line":266},2,[199,268,270],{"emptyLinePlaceholder":269},true,"\n",[199,272,274,278],{"class":201,"line":273},3,[199,275,277],{"class":276},"sfNiH","on",[199,279,280],{"class":259},":\n",[199,282,284,287],{"class":201,"line":283},4,[199,285,286],{"class":255},"  push",[199,288,280],{"class":259},[199,290,292,295,297,300,303],{"class":201,"line":291},5,[199,293,294],{"class":255},"    branches",[199,296,260],{"class":259},[199,298,299],{"class":259}," [",[199,301,302],{"class":209},"main",[199,304,305],{"class":259},"]\n",[199,307,309],{"class":201,"line":308},6,[199,310,270],{"emptyLinePlaceholder":269},[199,312,314,317],{"class":201,"line":313},7,[199,315,316],{"class":255},"jobs",[199,318,280],{"class":259},[199,320,322,325],{"class":201,"line":321},8,[199,323,324],{"class":255},"  deploy",[199,326,280],{"class":259},[199,328,330,333,335],{"class":201,"line":329},9,[199,331,332],{"class":255},"    runs-on",[199,334,260],{"class":259},[199,336,337],{"class":209}," ubuntu-latest\n",[199,339,341,344],{"class":201,"line":340},10,[199,342,343],{"class":255},"    steps",[199,345,280],{"class":259},[199,347,349,352,355,357],{"class":201,"line":348},11,[199,350,351],{"class":259},"      -",[199,353,354],{"class":255}," uses",[199,356,260],{"class":259},[199,358,359],{"class":209}," actions\u002Fcheckout@v4\n",[199,361,363,365,368,370],{"class":201,"line":362},12,[199,364,351],{"class":259},[199,366,367],{"class":255}," run",[199,369,260],{"class":259},[199,371,372],{"class":209}," npm ci && npm test\n",[199,374,376,378,381,383],{"class":201,"line":375},13,[199,377,351],{"class":259},[199,379,380],{"class":255}," name",[199,382,260],{"class":259},[199,384,385],{"class":209}," Deploy to Harblet\n",[199,387,389,392,394],{"class":201,"line":388},14,[199,390,391],{"class":255},"        run",[199,393,260],{"class":259},[199,395,396],{"class":209}," curl --fail -X POST \"${{ secrets.HARBLET_DEPLOY_HOOK }}\"\n",[232,398,401,407],{"icon":399,"label":400},"i-simple-icons-gitlab","GitLab CI",[136,402,403,404,406],{},"Add the URL as a masked CI\u002FCD variable named ",[145,405,241],{},", then add a job:",[190,408,411],{"className":245,"code":409,"filename":410,"language":248,"meta":195,"style":195},"deploy:\n  stage: deploy\n  image: curlimages\u002Fcurl\n  script:\n    - curl --fail -X POST \"$HARBLET_DEPLOY_HOOK\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\"\n",".gitlab-ci.yml",[145,412,413,420,430,440,447,455,462],{"__ignoreMap":195},[199,414,415,418],{"class":201,"line":202},[199,416,417],{"class":255},"deploy",[199,419,280],{"class":259},[199,421,422,425,427],{"class":201,"line":266},[199,423,424],{"class":255},"  stage",[199,426,260],{"class":259},[199,428,429],{"class":209}," deploy\n",[199,431,432,435,437],{"class":201,"line":273},[199,433,434],{"class":255},"  image",[199,436,260],{"class":259},[199,438,439],{"class":209}," curlimages\u002Fcurl\n",[199,441,442,445],{"class":201,"line":283},[199,443,444],{"class":255},"  script",[199,446,280],{"class":259},[199,448,449,452],{"class":201,"line":291},[199,450,451],{"class":259},"    -",[199,453,454],{"class":209}," curl --fail -X POST \"$HARBLET_DEPLOY_HOOK\"\n",[199,456,457,460],{"class":201,"line":308},[199,458,459],{"class":255},"  rules",[199,461,280],{"class":259},[199,463,464,466,469,471],{"class":201,"line":313},[199,465,451],{"class":259},[199,467,468],{"class":255}," if",[199,470,260],{"class":259},[199,472,473],{"class":209}," $CI_COMMIT_BRANCH == \"main\"\n",[174,475,477],{"id":476},"responses","Responses",[479,480,481,494],"table",{},[482,483,484],"thead",{},[485,486,487,491],"tr",{},[488,489,490],"th",{},"Status",[488,492,493],{},"Meaning",[495,496,497,528,538,548],"tbody",{},[485,498,499,505],{},[500,501,502],"td",{},[145,503,504],{},"201",[500,506,507,508,511,512,515,516,519,520,523,524,527],{},"The deployment started. The body holds its ",[145,509,510],{},"id"," and its ",[145,513,514],{},"status",": ",[145,517,518],{},"queued",", ",[145,521,522],{},"building"," or ",[145,525,526],{},"deploying",".",[485,529,530,535],{},[500,531,532],{},[145,533,534],{},"500",[500,536,537],{},"The deployment failed to start.",[485,539,540,545],{},[500,541,542],{},[145,543,544],{},"400",[500,546,547],{},"The URL is incomplete or mistyped, for example a character got lost when copying it.",[485,549,550,555],{},[500,551,552],{},[145,553,554],{},"404",[500,556,557],{},"No service has this deploy hook. The URL may have been regenerated.",[136,559,560,563],{},[145,561,562],{},"curl --fail"," exits with an error on any status from 400 up, so your pipeline fails when the deployment can't start.",[190,565,569],{"className":566,"code":567,"language":568,"meta":195,"style":195},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{ \"id\": \"019a8f3c-5b2d-7e41-9c3a-2d4b6e8f0a1c\", \"status\": \"building\" }\n","json",[145,570,571],{"__ignoreMap":195},[199,572,573,576,579,582,585,587,589,592,594,597,599,601,603,605,607,609,611],{"class":201,"line":202},[199,574,575],{"class":259},"{",[199,577,578],{"class":259}," \"",[199,580,510],{"class":581},"spNyl",[199,583,584],{"class":259},"\"",[199,586,260],{"class":259},[199,588,578],{"class":259},[199,590,591],{"class":209},"019a8f3c-5b2d-7e41-9c3a-2d4b6e8f0a1c",[199,593,584],{"class":259},[199,595,596],{"class":259},",",[199,598,578],{"class":259},[199,600,514],{"class":581},[199,602,584],{"class":259},[199,604,260],{"class":259},[199,606,578],{"class":259},[199,608,522],{"class":209},[199,610,584],{"class":259},[199,612,613],{"class":259}," }\n",[615,616,617,618,621,622,624,625,527],"note",{},"The hook answers as soon as the deployment has started. It doesn't wait for the build or the rollout to finish. Follow those on the service's ",[140,619,620],{},"Deployments"," tab, where hook deployments show ",[140,623,187],{}," under ",[140,626,627],{},"Started by",[174,629,631],{"id":630},"several-calls-in-a-row","Several calls in a row",[136,633,634,635,637],{},"The hook follows the same rules as the ",[140,636,26],{}," button: a service runs one deployment at a time, and a newer queued deployment replaces an older one. Since every build takes the newest commit of the branch, several pushes in a row end on the newest commit.",[136,639,640,641,643],{},"The request body is ignored, and only ",[145,642,147],{}," deploys. Opening the URL in a browser doesn't.",[174,645,647],{"id":646},"regenerate-the-url","Regenerate the URL",[136,649,650,651,654,655,657],{},"If the URL leaked, click ",[140,652,653],{},"Regenerate"," on the ",[140,656,187],{}," card and confirm. The old URL stops working right away, so update the secret in your pipelines.",[615,659,660,661,665],{},"The URL starts with Harblet's address. After you give Harblet ",[662,663,664],"a",{"href":97},"its own domain",", copy the new URL into your pipelines. The old URL with the server's IP address keeps working only while port 3000 is open.",[667,668,669],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":195,"searchDepth":266,"depth":266,"links":671},[672,673,674,675,676],{"id":176,"depth":266,"text":177},{"id":226,"depth":266,"text":227},{"id":476,"depth":266,"text":477},{"id":630,"depth":266,"text":631},{"id":646,"depth":266,"text":647},"Deploy a service from your CI pipeline with one POST request.","md",null,{},{"icon":64},{"title":61,"description":677},"Q1wBK9mTzIsrvCz17cGX_UzQNleL-5UT0-ZDDdbMyjc",[685,687],{"title":56,"path":57,"stem":58,"description":686,"icon":59,"children":-1},"Follow builds and rollouts, read live logs, and redeploy earlier versions.",{"title":66,"path":67,"stem":68,"description":688,"icon":69,"children":-1},"Point your domains at a service and secure them with your own certificates.",1794744117395]