[{"data":1,"prerenderedAt":1698},["ShallowReactive",2],{"navigation":3,"\u002Fdeployment":604,"\u002Fdeployment-surround":1693},[4,24,67,93,236,533],{"title":5,"path":6,"stem":7,"children":8,"collapsed":23},"Getting Started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,11,15,19],{"title":10,"path":6,"stem":7},"Introduction",{"title":12,"path":13,"stem":14},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":16,"path":17,"stem":18},"Key Ideas","\u002Fgetting-started\u002Fkey-ideas","1.getting-started\u002F3.key-ideas",{"title":20,"path":21,"stem":22},"Releases","\u002Fgetting-started\u002Freleases","1.getting-started\u002F4.releases",true,{"title":25,"path":26,"stem":27,"children":28,"collapsed":23},"Core Concepts","\u002Fcore-concepts","2.core-concepts\u002F0.index",[29,31,35,39,43,47,51,55,59,63],{"title":30,"path":26,"stem":27},"Overview",{"title":32,"path":33,"stem":34},"How It All Works","\u002Fcore-concepts\u002Farchitecture","2.core-concepts\u002F1.architecture",{"title":36,"path":37,"stem":38},"The Data Model","\u002Fcore-concepts\u002Fthe-data-model","2.core-concepts\u002F2.the-data-model",{"title":40,"path":41,"stem":42},"Layouts & Pages","\u002Fcore-concepts\u002Flayouts-and-pages","2.core-concepts\u002F3.layouts-and-pages",{"title":44,"path":45,"stem":46},"Dynamic Pages","\u002Fcore-concepts\u002Fdynamic-pages","2.core-concepts\u002F4.dynamic-pages",{"title":48,"path":49,"stem":50},"Components","\u002Fcore-concepts\u002Fcomponents","2.core-concepts\u002F5.components",{"title":52,"path":53,"stem":54},"Draft & Publish Workflow","\u002Fcore-concepts\u002Fdraft-and-publish","2.core-concepts\u002F6.draft-and-publish",{"title":56,"path":57,"stem":58},"The Admin Panel","\u002Fcore-concepts\u002Fadmin-panel","2.core-concepts\u002F7.admin-panel",{"title":60,"path":61,"stem":62},"Caching","\u002Fcore-concepts\u002Fcaching","2.core-concepts\u002F8.caching",{"title":64,"path":65,"stem":66},"Glossary","\u002Fcore-concepts\u002Fglossary","2.core-concepts\u002F9.glossary",{"title":68,"path":69,"stem":70,"children":71,"collapsed":23},"Guides","\u002Fguides","3.guides\u002F0.index",[72,73,77,81,85,89],{"title":30,"path":69,"stem":70},{"title":74,"path":75,"stem":76},"Your First Layout","\u002Fguides\u002Fyour-first-layout","3.guides\u002F1.your-first-layout",{"title":78,"path":79,"stem":80},"Your First Page Template","\u002Fguides\u002Fyour-first-page-template","3.guides\u002F2.your-first-page-template",{"title":82,"path":83,"stem":84},"Your First Component","\u002Fguides\u002Fyour-first-component","3.guides\u002F3.your-first-component",{"title":86,"path":87,"stem":88},"Alternative UI Variants","\u002Fguides\u002Falternative-ui-variants","3.guides\u002F4.alternative-ui-variants",{"title":90,"path":91,"stem":92},"Your First Dynamic Page","\u002Fguides\u002Fyour-first-dynamic-page","3.guides\u002F5.your-first-dynamic-page",{"title":94,"path":95,"stem":96,"children":97,"collapsed":23},"API Bundle (Back-End)","\u002Fapi","4.api\u002F0.index",[98,99,103,107,129,175,179,183,212,216,220,224,228,232],{"title":30,"path":95,"stem":96},{"title":100,"path":101,"stem":102},"Bundle Setup","\u002Fapi\u002Fbundle-setup","4.api\u002F02.bundle-setup",{"title":104,"path":105,"stem":106},"Configuration Reference","\u002Fapi\u002Fconfiguration","4.api\u002F03.configuration",{"title":108,"path":109,"stem":110,"children":111,"page":128},"Users","\u002Fapi\u002Fusers","4.api\u002F04.users",[112,116,120,124],{"title":113,"path":114,"stem":115},"Authentication","\u002Fapi\u002Fusers\u002Fauthentication","4.api\u002F04.users\u002F1.authentication",{"title":117,"path":118,"stem":119},"User Emails","\u002Fapi\u002Fusers\u002Fuser-emails","4.api\u002F04.users\u002F2.user-emails",{"title":121,"path":122,"stem":123},"Access Control","\u002Fapi\u002Fusers\u002Faccess-control","4.api\u002F04.users\u002F3.access-control",{"title":125,"path":126,"stem":127},"Sites with Non-Admin Users","\u002Fapi\u002Fusers\u002Fnon-admin-users","4.api\u002F04.users\u002F4.non-admin-users",false,{"title":48,"path":130,"stem":131,"children":132,"page":128},"\u002Fapi\u002Fcomponents","4.api\u002F05.components",[133,137,158,171],{"title":134,"path":135,"stem":136},"Creating Components","\u002Fapi\u002Fcomponents\u002Fcreating-components","4.api\u002F05.components\u002F1.creating-components",{"title":138,"path":139,"stem":140,"children":141,"page":128},"Annotations","\u002Fapi\u002Fcomponents\u002Fannotations","4.api\u002F05.components\u002F2.annotations",[142,146,150,154],{"title":143,"path":144,"stem":145},"Publishable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable","4.api\u002F05.components\u002F2.annotations\u002F1.publishable",{"title":147,"path":148,"stem":149},"Uploadable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fuploadable","4.api\u002F05.components\u002F2.annotations\u002F2.uploadable",{"title":151,"path":152,"stem":153},"Timestamped","\u002Fapi\u002Fcomponents\u002Fannotations\u002Ftimestamped","4.api\u002F05.components\u002F2.annotations\u002F3.timestamped",{"title":155,"path":156,"stem":157},"Explicit Allow Only","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fexplicit-allow-only","4.api\u002F05.components\u002F2.annotations\u002F4.explicit-allow-only",{"title":159,"path":160,"stem":161,"children":162,"page":128},"Built Ins","\u002Fapi\u002Fcomponents\u002Fbuilt-ins","4.api\u002F05.components\u002F3.built-ins",[163,167],{"title":164,"path":165,"stem":166},"Collection Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fcollection-component","4.api\u002F05.components\u002F3.built-ins\u002F1.collection-component",{"title":168,"path":169,"stem":170},"Form Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fform-component","4.api\u002F05.components\u002F3.built-ins\u002F2.form-component",{"title":172,"path":173,"stem":174},"Groups & Positions","\u002Fapi\u002Fcomponents\u002Fcomponent-groups","4.api\u002F05.components\u002F4.component-groups",{"title":176,"path":177,"stem":178},"Page Data & Nested Pages","\u002Fapi\u002Fdynamic-pages","4.api\u002F06.dynamic-pages",{"title":180,"path":181,"stem":182},"Routes","\u002Fapi\u002Froutes","4.api\u002F07.routes",{"title":184,"path":185,"stem":186,"children":187,"page":128},"Data Fixtures","\u002Fapi\u002Fdata-fixtures","4.api\u002F08.data-fixtures",[188,192,196,200,204,208],{"title":189,"path":190,"stem":191},"Getting Started with Fixtures","\u002Fapi\u002Fdata-fixtures\u002Fgetting-started","4.api\u002F08.data-fixtures\u002F1.getting-started",{"title":193,"path":194,"stem":195},"Writing a Scaffold","\u002Fapi\u002Fdata-fixtures\u002Fwriting-a-scaffold","4.api\u002F08.data-fixtures\u002F2.writing-a-scaffold",{"title":197,"path":198,"stem":199},"Builder Reference","\u002Fapi\u002Fdata-fixtures\u002Fbuilder-reference","4.api\u002F08.data-fixtures\u002F3.builder-reference",{"title":201,"path":202,"stem":203},"Seeding Content","\u002Fapi\u002Fdata-fixtures\u002Fseeding-content","4.api\u002F08.data-fixtures\u002F4.seeding-content",{"title":205,"path":206,"stem":207},"Appending & Multiple Scaffolds","\u002Fapi\u002Fdata-fixtures\u002Fappending","4.api\u002F08.data-fixtures\u002F5.appending",{"title":209,"path":210,"stem":211},"Generating Fixtures","\u002Fapi\u002Fdata-fixtures\u002Fgenerating-fixtures","4.api\u002F08.data-fixtures\u002F6.generating-fixtures",{"title":213,"path":214,"stem":215},"Real-Time (Mercure)","\u002Fapi\u002Freal-time","4.api\u002F09.real-time",{"title":217,"path":218,"stem":219},"Versions & Conflicts","\u002Fapi\u002Fversions-and-conflicts","4.api\u002F09.versions-and-conflicts",{"title":221,"path":222,"stem":223},"HTTP Caching","\u002Fapi\u002Fhttp-caching","4.api\u002F10.http-caching",{"title":225,"path":226,"stem":227},"Orphaned Data","\u002Fapi\u002Forphaned-data","4.api\u002F11.orphaned-data",{"title":229,"path":230,"stem":231},"Console Commands","\u002Fapi\u002Fconsole-commands","4.api\u002F12.console-commands",{"title":233,"path":234,"stem":235},"Debugging & Errors","\u002Fapi\u002Fdebugging","4.api\u002F13.debugging",{"title":237,"path":238,"stem":239,"children":240,"collapsed":23},"Nuxt Module (Front-End)","\u002Fnuxt-module","5.nuxt-module\u002F0.index",[241,242,246,259,279,308,329,460,494,497,525,529],{"title":30,"path":238,"stem":239},{"title":243,"path":244,"stem":245},"Module Setup","\u002Fnuxt-module\u002Fmodule-setup","5.nuxt-module\u002F01.module-setup",{"title":247,"path":248,"stem":249,"children":250,"page":128},"Configuration","\u002Fnuxt-module\u002Fconfiguration","5.nuxt-module\u002F02.configuration",[251,255],{"title":252,"path":253,"stem":254},"Nuxt Config","\u002Fnuxt-module\u002Fconfiguration\u002Fnuxt-config","5.nuxt-module\u002F02.configuration\u002F1.nuxt-config",{"title":256,"path":257,"stem":258},"Site Config & SEO","\u002Fnuxt-module\u002Fconfiguration\u002Fsite-config-and-seo","5.nuxt-module\u002F02.configuration\u002F2.site-config-and-seo",{"title":260,"path":261,"stem":262,"children":263,"page":128},"Building Your Ui","\u002Fnuxt-module\u002Fbuilding-your-ui","5.nuxt-module\u002F03.building-your-ui",[264,268,272,275],{"title":265,"path":266,"stem":267},"Layouts","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-layouts","5.nuxt-module\u002F03.building-your-ui\u002F1.creating-layouts",{"title":269,"path":270,"stem":271},"Page Templates","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-page-templates","5.nuxt-module\u002F03.building-your-ui\u002F2.creating-page-templates",{"title":48,"path":273,"stem":274},"\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-components","5.nuxt-module\u002F03.building-your-ui\u002F3.creating-components",{"title":276,"path":277,"stem":278},"CLI Generator","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcwa-cli","5.nuxt-module\u002F03.building-your-ui\u002F4.cwa-cli",{"title":280,"path":281,"stem":282,"children":283,"page":128},"Component Helpers","\u002Fnuxt-module\u002Fcomponent-helpers","5.nuxt-module\u002F04.component-helpers",[284,288,292,296,300,304],{"title":285,"path":286,"stem":287},"Images & Media","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fimages-and-uploads","5.nuxt-module\u002F04.component-helpers\u002F1.images-and-uploads",{"title":289,"path":290,"stem":291},"Collections & Pagination","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fcollections-and-pagination","5.nuxt-module\u002F04.component-helpers\u002F2.collections-and-pagination",{"title":293,"path":294,"stem":295},"HTML Content","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fhtml-content","5.nuxt-module\u002F04.component-helpers\u002F3.html-content",{"title":297,"path":298,"stem":299},"Rich-Text Editor","\u002Fnuxt-module\u002Fcomponent-helpers\u002Frich-text-editor","5.nuxt-module\u002F04.component-helpers\u002F4.rich-text-editor",{"title":301,"path":302,"stem":303},"Real-Time Updates","\u002Fnuxt-module\u002Fcomponent-helpers\u002Freal-time-updates","5.nuxt-module\u002F04.component-helpers\u002F5.real-time-updates",{"title":305,"path":306,"stem":307},"Forms","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fforms","5.nuxt-module\u002F04.component-helpers\u002F6.forms",{"title":309,"path":310,"stem":311,"children":312,"page":128},"Cwa Components","\u002Fnuxt-module\u002Fcwa-components","5.nuxt-module\u002F05.cwa-components",[313,317,321,325],{"title":314,"path":315,"stem":316},"\u003CCwaComponentGroup \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-component-group","5.nuxt-module\u002F05.cwa-components\u002F1.cwa-component-group",{"title":318,"path":319,"stem":320},"\u003CCwaPage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-page","5.nuxt-module\u002F05.cwa-components\u002F2.cwa-page",{"title":322,"path":323,"stem":324},"\u003CCwaLink \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-link","5.nuxt-module\u002F05.cwa-components\u002F3.cwa-link",{"title":326,"path":327,"stem":328},"\u003CCwaDefaultLayout \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-default-layout","5.nuxt-module\u002F05.cwa-components\u002F5.cwa-default-layout",{"title":330,"path":331,"stem":332,"children":333,"page":128},"Composables","\u002Fnuxt-module\u002Fcomposables","5.nuxt-module\u002F06.composables",[334,337,345,370,390,415,435],{"title":30,"path":335,"stem":336},"\u002Fnuxt-module\u002Fcomposables\u002Foverview","5.nuxt-module\u002F06.composables\u002F0.overview",{"title":338,"path":339,"stem":340,"children":341,"page":128},"Layout","\u002Fnuxt-module\u002Fcomposables\u002Flayout","5.nuxt-module\u002F06.composables\u002F1.layout",[342],{"title":338,"path":343,"stem":344},"\u002Fnuxt-module\u002Fcomposables\u002Flayout\u002Fuse-cwa-layout","5.nuxt-module\u002F06.composables\u002F1.layout\u002F1.use-cwa-layout",{"title":346,"path":347,"stem":348,"children":349,"page":128},"Component","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent","5.nuxt-module\u002F06.composables\u002F2.component",[350,354,358,362,366],{"title":351,"path":352,"stem":353},"Component (recommended)","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-component","5.nuxt-module\u002F06.composables\u002F2.component\u002F1.use-cwa-component",{"title":355,"path":356,"stem":357},"Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-resource","5.nuxt-module\u002F06.composables\u002F2.component\u002F2.use-cwa-resource",{"title":359,"path":360,"stem":361},"File Field","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-file-field","5.nuxt-module\u002F06.composables\u002F2.component\u002F3.use-cwa-file-field",{"title":363,"path":364,"stem":365},"Collection Pagination","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-pagination","5.nuxt-module\u002F06.composables\u002F2.component\u002F4.use-cwa-collection-pagination",{"title":367,"path":368,"stem":369},"Collection Resource (deprecated)","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-resource","5.nuxt-module\u002F06.composables\u002F2.component\u002F9.use-cwa-collection-resource",{"title":371,"path":372,"stem":373,"children":374,"page":128},"Form","\u002Fnuxt-module\u002Fcomposables\u002Fform","5.nuxt-module\u002F06.composables\u002F3.form",[375,378,382,386],{"title":371,"path":376,"stem":377},"\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form","5.nuxt-module\u002F06.composables\u002F3.form\u002F1.use-cwa-form",{"title":379,"path":380,"stem":381},"Form Input","\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form-input","5.nuxt-module\u002F06.composables\u002F3.form\u002F2.use-cwa-form-input",{"title":383,"path":384,"stem":385},"Form Repeated","\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form-repeated","5.nuxt-module\u002F06.composables\u002F3.form\u002F3.use-cwa-form-repeated",{"title":387,"path":388,"stem":389},"Form Collection","\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form-collection","5.nuxt-module\u002F06.composables\u002F3.form\u002F4.use-cwa-form-collection",{"title":391,"path":392,"stem":393,"children":394,"page":128},"Admin Manager","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager","5.nuxt-module\u002F06.composables\u002F4.admin-manager",[395,399,403,407,411],{"title":396,"path":397,"stem":398},"Manager Tab","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-manager-tab","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F1.use-cwa-resource-manager-tab",{"title":400,"path":401,"stem":402},"Resource Model","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-model","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F2.use-cwa-resource-model",{"title":404,"path":405,"stem":406},"Resource Upload","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-upload","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F3.use-cwa-resource-upload",{"title":408,"path":409,"stem":410},"Remote Changes","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fon-remote-change","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F4.on-remote-change",{"title":412,"path":413,"stem":414},"Real-Time Events","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-realtime","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F5.use-cwa-realtime",{"title":416,"path":417,"stem":418,"children":419,"page":128},"Utilities","\u002Fnuxt-module\u002Fcomposables\u002Futilities","5.nuxt-module\u002F06.composables\u002F5.utilities",[420,424,428,432],{"title":421,"path":422,"stem":423},"Resource Endpoint","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-endpoint","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F1.use-cwa-resource-endpoint",{"title":425,"path":426,"stem":427},"Query Model","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-query-bound-model","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F2.use-query-bound-model",{"title":429,"path":430,"stem":431},"Resource Route","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-route","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F3.use-cwa-resource-route",{"title":293,"path":433,"stem":434},"\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-html-content","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F4.use-html-content",{"title":436,"path":437,"stem":438,"children":439,"page":128},"Auth","\u002Fnuxt-module\u002Fcomposables\u002Fauth","5.nuxt-module\u002F06.composables\u002F6.auth",[440,444,448,452,456],{"title":441,"path":442,"stem":443},"Login","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-login","5.nuxt-module\u002F06.composables\u002F6.auth\u002F1.use-login",{"title":445,"path":446,"stem":447},"Forgot Password","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-forgot-password","5.nuxt-module\u002F06.composables\u002F6.auth\u002F2.use-forgot-password",{"title":449,"path":450,"stem":451},"Reset Password","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-reset-password","5.nuxt-module\u002F06.composables\u002F6.auth\u002F3.use-reset-password",{"title":453,"path":454,"stem":455},"Verify Email","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-verify-email","5.nuxt-module\u002F06.composables\u002F6.auth\u002F4.use-verify-email",{"title":457,"path":458,"stem":459},"Resend Verify Email","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-resend-verify-email","5.nuxt-module\u002F06.composables\u002F6.auth\u002F5.use-resend-verify-email",{"title":461,"path":462,"stem":463,"children":464,"page":128},"Cwa Api","\u002Fnuxt-module\u002Fcwa-api","5.nuxt-module\u002F07.cwa-api",[465,468,472,476,479,482,486,490],{"title":30,"path":466,"stem":467},"\u002Fnuxt-module\u002Fcwa-api\u002Foverview","5.nuxt-module\u002F07.cwa-api\u002F1.overview",{"title":469,"path":470,"stem":471},"Resources","\u002Fnuxt-module\u002Fcwa-api\u002Fresources","5.nuxt-module\u002F07.cwa-api\u002F2.resources",{"title":473,"path":474,"stem":475},"Resources Manager","\u002Fnuxt-module\u002Fcwa-api\u002Fresources-manager","5.nuxt-module\u002F07.cwa-api\u002F3.resources-manager",{"title":436,"path":477,"stem":478},"\u002Fnuxt-module\u002Fcwa-api\u002Fauth","5.nuxt-module\u002F07.cwa-api\u002F4.auth",{"title":305,"path":480,"stem":481},"\u002Fnuxt-module\u002Fcwa-api\u002Fforms","5.nuxt-module\u002F07.cwa-api\u002F5.forms",{"title":483,"path":484,"stem":485},"Admin","\u002Fnuxt-module\u002Fcwa-api\u002Fadmin","5.nuxt-module\u002F07.cwa-api\u002F6.admin",{"title":487,"path":488,"stem":489},"Site Config","\u002Fnuxt-module\u002Fcwa-api\u002Fsite-config","5.nuxt-module\u002F07.cwa-api\u002F7.site-config",{"title":491,"path":492,"stem":493},"Orphaned Resources","\u002Fnuxt-module\u002Fcwa-api\u002Forphaned-resources","5.nuxt-module\u002F07.cwa-api\u002F8.orphaned-resources",{"title":113,"path":495,"stem":496},"\u002Fnuxt-module\u002Fauthentication","5.nuxt-module\u002F08.authentication",{"title":498,"path":499,"stem":500,"children":501,"page":128},"Cwa Layer","\u002Fnuxt-module\u002Fcwa-layer","5.nuxt-module\u002F9.cwa-layer",[502,505,509,513,517,521],{"title":30,"path":503,"stem":504},"\u002Fnuxt-module\u002Fcwa-layer\u002Foverview","5.nuxt-module\u002F9.cwa-layer\u002F1.overview",{"title":506,"path":507,"stem":508},"Auth Pages","\u002Fnuxt-module\u002Fcwa-layer\u002Fauth-pages","5.nuxt-module\u002F9.cwa-layer\u002F2.auth-pages",{"title":510,"path":511,"stem":512},"Admin Panel","\u002Fnuxt-module\u002Fcwa-layer\u002Fadmin-panel","5.nuxt-module\u002F9.cwa-layer\u002F3.admin-panel",{"title":514,"path":515,"stem":516},"Styling","\u002Fnuxt-module\u002Fcwa-layer\u002Fstyling","5.nuxt-module\u002F9.cwa-layer\u002F4.styling",{"title":518,"path":519,"stem":520},"Date Pickers","\u002Fnuxt-module\u002Fcwa-layer\u002Fdate-pickers","5.nuxt-module\u002F9.cwa-layer\u002F5.date-pickers",{"title":522,"path":523,"stem":524},"Maintenance","\u002Fnuxt-module\u002Fcwa-layer\u002Fmaintenance","5.nuxt-module\u002F9.cwa-layer\u002F6.maintenance",{"title":526,"path":527,"stem":528},"PWA & Offline","\u002Fnuxt-module\u002Fpwa","5.nuxt-module\u002F91.pwa",{"title":530,"path":531,"stem":532},"Page Caching","\u002Fnuxt-module\u002Fpage-caching","5.nuxt-module\u002F92.page-caching",{"title":534,"path":535,"stem":536,"children":537,"collapsed":23},"Deployment & Operations","\u002Fdeployment","6.deployment\u002F0.index",[538,540,544,548,552,556,560,564,568,572,576,580,584,588,592,596,600],{"title":539,"path":535,"stem":536},"Deploying a CWA Site",{"title":541,"path":542,"stem":543},"Docker","\u002Fdeployment\u002Fdocker","6.deployment\u002F1.docker",{"title":545,"path":546,"stem":547},"Deploy to One Server","\u002Fdeployment\u002Fone-server","6.deployment\u002F1.one-server",{"title":549,"path":550,"stem":551},"Kubernetes & Helm","\u002Fdeployment\u002Fkubernetes","6.deployment\u002F2.kubernetes",{"title":553,"path":554,"stem":555},"Moving From One Server to Kubernetes","\u002Fdeployment\u002Fmoving-to-kubernetes","6.deployment\u002F2.moving-to-kubernetes",{"title":557,"path":558,"stem":559},"Scaled Mode","\u002Fdeployment\u002Fscaled-mode","6.deployment\u002F2.scaled-mode",{"title":561,"path":562,"stem":563},"CI\u002FCD","\u002Fdeployment\u002Fci-cd","6.deployment\u002F3.ci-cd",{"title":565,"path":566,"stem":567},"Migrations and Backups","\u002Fdeployment\u002Fmigrations-and-backups","6.deployment\u002F3.migrations-and-backups",{"title":569,"path":570,"stem":571},"CI\u002FCD Variables","\u002Fdeployment\u002Fvariables","6.deployment\u002F4.variables",{"title":573,"path":574,"stem":575},"Cloudflare","\u002Fdeployment\u002Fcloudflare","6.deployment\u002F5.cloudflare",{"title":577,"path":578,"stem":579},"Origin Protection","\u002Fdeployment\u002Forigin-protection","6.deployment\u002F5.origin-protection",{"title":581,"path":582,"stem":583},"Load Testing","\u002Fdeployment\u002Fload-testing","6.deployment\u002F6.load-testing",{"title":585,"path":586,"stem":587},"Performance Audit","\u002Fdeployment\u002Fperformance-audit","6.deployment\u002F6.performance-audit",{"title":589,"path":590,"stem":591},"Reading Lighthouse Scores","\u002Fdeployment\u002Freading-lighthouse-scores","6.deployment\u002F6.reading-lighthouse-scores",{"title":593,"path":594,"stem":595},"Browser Tests","\u002Fdeployment\u002Fbrowser-tests","6.deployment\u002F7.browser-tests",{"title":597,"path":598,"stem":599},"Faster Functional Tests","\u002Fdeployment\u002Ffaster-functional-tests","6.deployment\u002F7.faster-functional-tests",{"title":601,"path":602,"stem":603},"Troubleshooting","\u002Fdeployment\u002Ftroubleshooting","6.deployment\u002F7.troubleshooting",{"id":605,"title":539,"badge":606,"body":607,"description":1688,"extension":1689,"links":606,"meta":1690,"navigation":23,"path":535,"seo":1691,"stem":536,"__hash__":1692},"docs\u002F6.deployment\u002F0.index.md",null,{"type":608,"value":609,"toc":1675},"minimark",[610,619,717,737,740,743,748,751,844,855,858,1132,1136,1139,1164,1176,1180,1191,1211,1215,1218,1243,1254,1262,1279,1285,1289,1300,1304,1321,1324,1347,1354,1358,1370,1374,1497,1509,1513,1671],[611,612,613,614,618],"p",{},"A project made with ",[615,616,617],"code",{},"create-cwa"," can run in production in two ways. Pick one first:",[620,621,622,637],"table",{},[623,624,625],"thead",{},[626,627,628,631,634],"tr",{},[629,630],"th",{},[629,632,633],{},"One server with Docker Compose",[629,635,636],{},"Kubernetes with Helm",[638,639,640,659,679,692],"tbody",{},[626,641,642,649,654],{},[643,644,645],"td",{},[646,647,648],"strong",{},"Status",[643,650,651],{},[646,652,653],{},"Preview",[643,655,656],{},[646,657,658],{},"Supported",[626,660,661,666,676],{},[643,662,663],{},[646,664,665],{},"What runs it",[643,667,668,671,672,675],{},[615,669,670],{},"compose.prod.yaml"," on one Linux server, deployed by the template's ",[615,673,674],{},"bin\u002Fserver\u002F"," scripts",[643,677,678],{},"The template's Helm chart, deployed by its GitLab CI or GitHub Actions pipeline",[626,680,681,686,689],{},[643,682,683],{},[646,684,685],{},"Scaling",[643,687,688],{},"One server",[643,690,691],{},"The front end autoscales, and scaled mode runs several API pods",[626,693,694,699,709],{},[643,695,696],{},[646,697,698],{},"Read",[643,700,701,704,705],{},[702,703,545],"a",{"href":546},", then ",[702,706,708],{"href":707},"\u002Fdeployment\u002Fdocker#production-docker-compose","Docker › Production Docker Compose",[643,710,711,712,714,715],{},"The steps below, then ",[702,713,549],{"href":550}," and ",[702,716,561],{"href":562},[718,719,722],"callout",{"icon":720,"color":721},"i-heroicons-exclamation-triangle","warning",[611,723,724,727,728,730,731,733,734,736],{},[646,725,726],{},"One server is a preview."," The template's ",[615,729,674],{}," scripts set up, deploy, back up and restore a site on one server, and media is stored on the server, but the scripts haven't run a production site yet. They assume a plain Linux server, such as Debian or Ubuntu, with Docker installed, and no particular hosting provider. See ",[702,732,545],{"href":546},", and ",[702,735,553],{"href":554}," when you outgrow it.",[611,738,739],{},"Kubernetes is the supported way to run a site, and the way to scale one. The pipeline builds the images, runs the tests, and deploys to Kubernetes with Helm. The rest of this page takes a new site to production on Kubernetes in order. Each step links to the page that explains it in full.",[741,742],"diagram-first-deploy",{},[744,745,747],"h2",{"id":746},"prepare-the-cluster","Prepare the cluster",[611,749,750],{},"The pipeline deploys into a cluster you already run. It doesn't install anything cluster-wide, so set these up once:",[752,753,754,769,794,821],"ul",{},[755,756,757,760,761,764,765,768],"li",{},[646,758,759],{},"A Kubernetes cluster."," The deploy jobs install kubectl ",[615,762,763],{},"1.31.0"," and Helm ",[615,766,767],{},"3.19.0"," by default. The daily orphan scan's time zone needs Kubernetes 1.27 or later.",[755,770,771,780,781,784,785,788,789,793],{},[646,772,773,779],{},[702,774,778],{"href":775,"rel":776},"https:\u002F\u002Fkubernetes.github.io\u002Fingress-nginx\u002Fdeploy\u002F",[777],"nofollow","ingress-nginx","."," The pipeline writes ingress-nginx annotations, and its rate limit and ",[615,782,783],{},"www"," redirect settings are ingress-nginx's. Give the controller's Service ",[615,786,787],{},"externalTrafficPolicy: Local",", ideally with 2 replicas and a PodDisruptionBudget. Otherwise every visitor looks internal and Caddy's per-visitor rate limit never applies (see ",[702,790,792],{"href":791},"\u002Fdeployment\u002Forigin-protection#ingress-rate-limits","Origin Protection › Ingress rate limits",").",[755,795,796,810,811,814,815,818,819,779],{},[646,797,798,803,804,714,807,779],{},[702,799,802],{"href":800,"rel":801},"https:\u002F\u002Fcert-manager.io\u002Fdocs\u002Finstallation\u002F",[777],"cert-manager"," with two ClusterIssuers, named exactly ",[615,805,806],{},"letsencrypt-staging",[615,808,809],{},"letsencrypt-prod"," The pipeline names the issuer in the ingress's ",[615,812,813],{},"cert-manager.io\u002Fcluster-issuer"," annotation, from ",[615,816,817],{},"CWA_CI_CLUSTER_ISSUER",", but never creates it. It defaults to ",[615,820,806],{},[755,822,823,826,827,832,833,836,837,840,841,843],{},[646,824,825],{},"A way for CI to reach the cluster."," On GitLab, a ",[702,828,831],{"href":829,"rel":830},"https:\u002F\u002Fdocs.gitlab.com\u002Fuser\u002Fclusters\u002Fagent\u002F",[777],"GitLab agent"," whose context you set as ",[615,834,835],{},"KUBE_CONTEXT",". On GitHub, a kubeconfig in the ",[615,838,839],{},"KUBECONFIG"," secret, and its context in the ",[615,842,835],{}," secret.",[718,845,846],{"icon":720,"color":721},[611,847,848,851,852,854],{},[646,849,850],{},"The ClusterIssuer names must match."," A ClusterIssuer with any other name is never used, and no certificate is issued. If yours have other names, set ",[615,853,817],{}," to the name on every deploy.",[611,856,857],{},"The issuers use Let's Encrypt's HTTP-01 challenge through ingress-nginx. A minimal pair, following cert-manager's own examples (use your own email address):",[859,860,865],"pre",{"className":861,"code":862,"language":863,"meta":864,"style":864},"language-yaml shiki shiki-themes github-light github-dark material-theme-palenight","apiVersion: cert-manager.io\u002Fv1\nkind: ClusterIssuer\nmetadata:\n  name: letsencrypt-staging\nspec:\n  acme:\n    server: https:\u002F\u002Facme-staging-v02.api.letsencrypt.org\u002Fdirectory\n    email: ops@example.com\n    privateKeySecretRef:\n      name: letsencrypt-staging\n    solvers:\n      - http01:\n          ingress:\n            ingressClassName: nginx\n---\napiVersion: cert-manager.io\u002Fv1\nkind: ClusterIssuer\nmetadata:\n  name: letsencrypt-prod\nspec:\n  acme:\n    server: https:\u002F\u002Facme-v02.api.letsencrypt.org\u002Fdirectory\n    email: ops@example.com\n    privateKeySecretRef:\n      name: letsencrypt-prod\n    solvers:\n      - http01:\n          ingress:\n            ingressClassName: nginx\n","yaml","",[615,866,867,884,895,904,915,923,931,942,953,961,971,979,990,998,1009,1016,1025,1034,1041,1051,1058,1065,1075,1084,1091,1100,1107,1116,1123],{"__ignoreMap":864},[868,869,872,876,880],"span",{"class":870,"line":871},"line",1,[868,873,875],{"class":874},"s-h7I","apiVersion",[868,877,879],{"class":878},"sOvfz",":",[868,881,883],{"class":882},"sLL54"," cert-manager.io\u002Fv1\n",[868,885,887,890,892],{"class":870,"line":886},2,[868,888,889],{"class":874},"kind",[868,891,879],{"class":878},[868,893,894],{"class":882}," ClusterIssuer\n",[868,896,898,901],{"class":870,"line":897},3,[868,899,900],{"class":874},"metadata",[868,902,903],{"class":878},":\n",[868,905,907,910,912],{"class":870,"line":906},4,[868,908,909],{"class":874},"  name",[868,911,879],{"class":878},[868,913,914],{"class":882}," letsencrypt-staging\n",[868,916,918,921],{"class":870,"line":917},5,[868,919,920],{"class":874},"spec",[868,922,903],{"class":878},[868,924,926,929],{"class":870,"line":925},6,[868,927,928],{"class":874},"  acme",[868,930,903],{"class":878},[868,932,934,937,939],{"class":870,"line":933},7,[868,935,936],{"class":874},"    server",[868,938,879],{"class":878},[868,940,941],{"class":882}," https:\u002F\u002Facme-staging-v02.api.letsencrypt.org\u002Fdirectory\n",[868,943,945,948,950],{"class":870,"line":944},8,[868,946,947],{"class":874},"    email",[868,949,879],{"class":878},[868,951,952],{"class":882}," ops@example.com\n",[868,954,956,959],{"class":870,"line":955},9,[868,957,958],{"class":874},"    privateKeySecretRef",[868,960,903],{"class":878},[868,962,964,967,969],{"class":870,"line":963},10,[868,965,966],{"class":874},"      name",[868,968,879],{"class":878},[868,970,914],{"class":882},[868,972,974,977],{"class":870,"line":973},11,[868,975,976],{"class":874},"    solvers",[868,978,903],{"class":878},[868,980,982,985,988],{"class":870,"line":981},12,[868,983,984],{"class":878},"      -",[868,986,987],{"class":874}," http01",[868,989,903],{"class":878},[868,991,993,996],{"class":870,"line":992},13,[868,994,995],{"class":874},"          ingress",[868,997,903],{"class":878},[868,999,1001,1004,1006],{"class":870,"line":1000},14,[868,1002,1003],{"class":874},"            ingressClassName",[868,1005,879],{"class":878},[868,1007,1008],{"class":882}," nginx\n",[868,1010,1012],{"class":870,"line":1011},15,[868,1013,1015],{"class":1014},"sRCss","---\n",[868,1017,1019,1021,1023],{"class":870,"line":1018},16,[868,1020,875],{"class":874},[868,1022,879],{"class":878},[868,1024,883],{"class":882},[868,1026,1028,1030,1032],{"class":870,"line":1027},17,[868,1029,889],{"class":874},[868,1031,879],{"class":878},[868,1033,894],{"class":882},[868,1035,1037,1039],{"class":870,"line":1036},18,[868,1038,900],{"class":874},[868,1040,903],{"class":878},[868,1042,1044,1046,1048],{"class":870,"line":1043},19,[868,1045,909],{"class":874},[868,1047,879],{"class":878},[868,1049,1050],{"class":882}," letsencrypt-prod\n",[868,1052,1054,1056],{"class":870,"line":1053},20,[868,1055,920],{"class":874},[868,1057,903],{"class":878},[868,1059,1061,1063],{"class":870,"line":1060},21,[868,1062,928],{"class":874},[868,1064,903],{"class":878},[868,1066,1068,1070,1072],{"class":870,"line":1067},22,[868,1069,936],{"class":874},[868,1071,879],{"class":878},[868,1073,1074],{"class":882}," https:\u002F\u002Facme-v02.api.letsencrypt.org\u002Fdirectory\n",[868,1076,1078,1080,1082],{"class":870,"line":1077},23,[868,1079,947],{"class":874},[868,1081,879],{"class":878},[868,1083,952],{"class":882},[868,1085,1087,1089],{"class":870,"line":1086},24,[868,1088,958],{"class":874},[868,1090,903],{"class":878},[868,1092,1094,1096,1098],{"class":870,"line":1093},25,[868,1095,966],{"class":874},[868,1097,879],{"class":878},[868,1099,1050],{"class":882},[868,1101,1103,1105],{"class":870,"line":1102},26,[868,1104,976],{"class":874},[868,1106,903],{"class":878},[868,1108,1110,1112,1114],{"class":870,"line":1109},27,[868,1111,984],{"class":878},[868,1113,987],{"class":874},[868,1115,903],{"class":878},[868,1117,1119,1121],{"class":870,"line":1118},28,[868,1120,995],{"class":874},[868,1122,903],{"class":878},[868,1124,1126,1128,1130],{"class":870,"line":1125},29,[868,1127,1003],{"class":874},[868,1129,879],{"class":878},[868,1131,1008],{"class":882},[744,1133,1135],{"id":1134},"create-the-namespaces","Create the namespaces",[611,1137,1138],{},"The pipeline never creates namespaces. It only deploys into ones that exist, with role bindings for the identity CI deploys with:",[752,1140,1141,1158],{},[755,1142,1143,1146,1147,1150,1151,1154,1155,843],{},[646,1144,1145],{},"Production's namespace",", which staging and canary share. On GitLab it's ",[615,1148,1149],{},"\u003Cproject name>-production"," unless you set ",[615,1152,1153],{},"KUBE_NAMESPACE",". On GitHub, set its name in the ",[615,1156,1157],{},"KUBE_NAMESPACE_PRODUCTION",[755,1159,1160,1163],{},[646,1161,1162],{},"One namespace per branch"," that should get a review app. A branch without one is skipped, and its pipeline shows orange.",[611,1165,1166,1167,1171,1172,793],{},"How to create them, and the role binding to add, is in ",[702,1168,1170],{"href":1169},"\u002Fdeployment\u002Fci-cd#creating-a-namespace-for-a-branch","CI\u002FCD › Creating a namespace for a branch",". The CI identity also needs access to cert-manager's Certificates in production's namespace, so changing hostnames later causes no downtime (see ",[702,1173,1175],{"href":1174},"\u002Fdeployment\u002Fci-cd#permissions","CI\u002FCD › Permissions",[744,1177,1179],{"id":1178},"set-the-ci-variables","Set the CI variables",[611,1181,1182,1183,1186,1187,779],{},"The CLI sets up GitLab CI or GitHub Actions when you create the project. Set the few variables a new site needs: the cluster connection, the domain (",[615,1184,1185],{},"KUBE_INGRESS_BASE_DOMAIN","), an external database, the media bucket, the mailer and the first admin's password. The checklist is ",[702,1188,1190],{"href":1189},"\u002Fdeployment\u002Fvariables#minimum-for-a-new-site","CI\u002FCD Variables › Minimum for a new site",[718,1192,1194],{"icon":1193},"i-heroicons-light-bulb",[611,1195,1196,1199,1200,714,1203,1206,1207,793],{},[646,1197,1198],{},"Use an external database for a real site."," The in-cluster PostgreSQL keeps no data by default, so it loses everything when its pod is replaced. Set ",[615,1201,1202],{},"DATABASE_URL",[615,1204,1205],{},"CWA_CI_POSTGRES_ENABLED=\"false\""," (see ",[702,1208,1210],{"href":1209},"\u002Fdeployment\u002Fvariables#database","CI\u002FCD Variables › Database",[744,1212,1214],{"id":1213},"point-dns-at-the-ingress","Point DNS at the ingress",[611,1216,1217],{},"Let's Encrypt's HTTP-01 challenge must reach the cluster's ingress, so point these hostnames at the ingress controller's address:",[752,1219,1220,1230,1236],{},[755,1221,1222,1223,1225,1226,1229],{},"production: ",[615,1224,1185],{},", and any ",[615,1227,1228],{},"KUBE_INGRESS_ALIAS_DOMAINS",";",[755,1231,1232,1233,1229],{},"staging: ",[615,1234,1235],{},"staging.\u003CKUBE_INGRESS_BASE_DOMAIN>",[755,1237,1238,1239,1242],{},"review apps: ",[615,1240,1241],{},"\u003Cbranch>-review.\u003CKUBE_INGRESS_BASE_DOMAIN>",", usually through a wildcard record.",[611,1244,1245,1246,1249,1250,793],{},"If Cloudflare is in front, leave each record ",[646,1247,1248],{},"DNS only"," until its first certificate is issued (see ",[702,1251,1253],{"href":1252},"\u002Fdeployment\u002Fcloudflare#each-deploy-track","Cloudflare › Each deploy track",[744,1255,1257,1258,1261],{"id":1256},"push-main-and-check-staging","Push ",[615,1259,1260],{},"main"," and check staging",[611,1263,1264,1265,1267,1268,1271,1272,1206,1275,793],{},"A push to ",[615,1266,1260],{}," builds the images, runs the tests and deploys staging. On GitHub, staging runs only once you set the ",[615,1269,1270],{},"CWA_CI_STAGING_ENABLED"," variable to ",[615,1273,1274],{},"true",[702,1276,1278],{"href":1277},"\u002Fdeployment\u002Fvariables#pipeline-flags","Pipeline flags",[611,1280,1281,1282,1284],{},"Staging gets a certificate from ",[615,1283,806],{},", which browsers don't trust, so expect a certificate warning. That's on purpose: if a hostname or the DNS is wrong, the challenge fails against the staging issuer's generous limits instead of Let's Encrypt's production limits. Check that staging serves the site, warning aside.",[744,1286,1288],{"id":1287},"switch-to-trusted-certificates","Switch to trusted certificates",[611,1290,1291,1292,1295,1296,1299],{},"Once the domain points at the cluster and staging's certificate was issued, set ",[615,1293,1294],{},"CWA_CI_CLUSTER_ISSUER=letsencrypt-prod",", and keep it on every production site. On GitLab, a variable scoped to ",[615,1297,1298],{},"production"," reaches staging and canary too.",[744,1301,1303],{"id":1302},"deploy-production","Deploy production",[611,1305,1306,1307,1309,1310,1313,1314,1318,1319,779],{},"Production is a manual job: ",[646,1308,1298],{}," in GitLab's pipeline, or the ",[646,1311,1312],{},"Production"," workflow on GitHub, run from the Actions tab. On GitLab it waits for the builds and tests. Both remove staging and canary once production is deployed (see ",[702,1315,1317],{"href":1316},"\u002Fdeployment\u002Fci-cd#production","CI\u002FCD › Production","). Before later deploys, you can read production's pending migrations, and turn on a backup before they run: see ",[702,1320,565],{"href":566},[611,1322,1323],{},"For the first deploy only, load the fixtures, which create the scaffold pages and the first admin user:",[1325,1326,1327,1333,1344],"ol",{},[755,1328,1329,1330,779],{},"Set ",[615,1331,1332],{},"CWA_CI_FIXTURES_ENABLED=\"true\"",[755,1334,1335,1336,1339,1340,1343],{},"Deploy production. On GitLab, then start the manual ",[646,1337,1338],{},"load fixtures production"," job. On GitHub, the ",[646,1341,1342],{},"Load fixtures"," step runs after the deploy by itself.",[755,1345,1346],{},"Remove the variable. On GitHub the step runs after every deploy while it's set.",[611,1348,1349,1350,779],{},"Fixture loads append and never delete content. See ",[702,1351,1353],{"href":1352},"\u002Fdeployment\u002Fci-cd#fixtures-on-a-deploy","CI\u002FCD › Fixtures on a deploy",[744,1355,1357],{"id":1356},"optional-put-cloudflare-in-front","Optional: put Cloudflare in front",[611,1359,1360,1361,1365,1366,779],{},"Proxy only, with no edge caching, is the recommended start: ",[702,1362,1364],{"href":1363},"\u002Fdeployment\u002Fcloudflare#option-a-proxy-only","Cloudflare › Option A",". Turn on edge caching later, if you want it, with ",[702,1367,1369],{"href":1368},"\u002Fdeployment\u002Fcloudflare#option-b-proxy-with-edge-caching","Cloudflare › Option B",[744,1371,1373],{"id":1372},"check-the-site","Check the site",[752,1375,1376,1397,1456,1490],{},[755,1377,1378,1381,1382,1385,1386,1389,1390,1206,1393,793],{},[646,1379,1380],{},"The cache warm"," after the production deploy (on GitLab, in the ",[615,1383,1384],{},"image variants and warm production"," job) lists every sitemap page with its status. Any page that isn't ",[615,1387,1388],{},"200"," is listed under ",[615,1391,1392],{},"CACHE WARM FAILED",[702,1394,1396],{"href":1395},"\u002Fdeployment\u002Fci-cd#warming-the-cache-after-a-deploy","CI\u002FCD › Warming the cache after a deploy",[755,1398,1399,1402,1403,1406,1407,1410,1411,779,1414],{},[646,1400,1401],{},"Pages come from the cache."," Request a page twice: the second response's ",[615,1404,1405],{},"cache-status"," header shows a Souin hit. Behind Cloudflare's Option A, ",[615,1408,1409],{},"cf-cache-status"," is ",[615,1412,1413],{},"DYNAMIC",[859,1415,1419],{"className":1416,"code":1417,"language":1418,"meta":864,"style":864},"language-sh shiki shiki-themes github-light github-dark material-theme-palenight","curl -sI https:\u002F\u002Fwww.example.com\u002F | grep -i -E 'cf-cache-status|cache-status'\n","sh",[615,1420,1421],{"__ignoreMap":864},[868,1422,1423,1426,1430,1433,1437,1440,1443,1446,1450,1453],{"class":870,"line":871},[868,1424,1425],{"class":1014},"curl",[868,1427,1429],{"class":1428},"szhYu"," -sI",[868,1431,1432],{"class":882}," https:\u002F\u002Fwww.example.com\u002F",[868,1434,1436],{"class":1435},"sVlFx"," |",[868,1438,1439],{"class":1014}," grep",[868,1441,1442],{"class":1428}," -i",[868,1444,1445],{"class":1428}," -E",[868,1447,1449],{"class":1448},"seSrl"," '",[868,1451,1452],{"class":882},"cf-cache-status|cache-status",[868,1454,1455],{"class":1448},"'\n",[755,1457,1458,1461,1462,1465,1466,714,1469,1472,1473,1476,1477,1479,1480,1482,1483,1485,1486,793],{},[646,1459,1460],{},"You can sign in."," Sign in at ",[615,1463,1464],{},"\u002Flogin"," with ",[615,1467,1468],{},"ADMIN_USERNAME",[615,1470,1471],{},"ADMIN_PASSWORD",". If the deploy or the fixture load warned that the login is ",[615,1474,1475],{},"admin"," \u002F ",[615,1478,1475],{},", set ",[615,1481,1471],{}," and load the fixtures again: a password you change in the admin goes back to ",[615,1484,1471],{}," at the next fixture load (see ",[702,1487,1489],{"href":1488},"\u002Fdeployment\u002Fvariables#the-admin-password","CI\u002FCD Variables › The admin password",[755,1491,1492,1493,1496],{},"Optional: run the ",[702,1494,1495],{"href":586},"performance audit"," to see what a visitor experiences.",[718,1498,1500],{"icon":1499},"i-heroicons-photo",[611,1501,1502,1505,1506,1508],{},[646,1503,1504],{},"Image placeholder:"," a cache warm's log after a first production deploy, every page ",[615,1507,1388],{},", with its time to first byte.",[744,1510,1512],{"id":1511},"which-page-do-i-need","Which page do I need?",[620,1514,1515,1525],{},[623,1516,1517],{},[626,1518,1519,1522],{},[629,1520,1521],{},"I want to…",[629,1523,1524],{},"Page",[638,1526,1527,1536,1545,1554,1563,1572,1581,1590,1599,1608,1617,1626,1635,1644,1653,1662],{},[626,1528,1529,1532],{},[643,1530,1531],{},"Run the stack locally, or understand the compose files",[643,1533,1534],{},[702,1535,541],{"href":542},[626,1537,1538,1541],{},[643,1539,1540],{},"Deploy, back up and restore a site on one server (a preview)",[643,1542,1543],{},[702,1544,545],{"href":546},[626,1546,1547,1550],{},[643,1548,1549],{},"Move a site from one server to Kubernetes",[643,1551,1552],{},[702,1553,553],{"href":554},[626,1555,1556,1559],{},[643,1557,1558],{},"Understand what the Helm chart deploys and how it scales",[643,1560,1561],{},[702,1562,549],{"href":550},[626,1564,1565,1568],{},[643,1566,1567],{},"Understand the pipeline's stages, scripts, fixtures and hostname changes",[643,1569,1570],{},[702,1571,561],{"href":562},[626,1573,1574,1577],{},[643,1575,1576],{},"See pending migrations before a production deploy, back the database up, or close the site while it migrates",[643,1578,1579],{},[702,1580,565],{"href":566},[626,1582,1583,1586],{},[643,1584,1585],{},"Look up a CI variable, its default, or the Helm value it sets",[643,1587,1588],{},[702,1589,569],{"href":570},[626,1591,1592,1595],{},[643,1593,1594],{},"Put Cloudflare in front, with or without edge caching",[643,1596,1597],{},[702,1598,573],{"href":574},[626,1600,1601,1604],{},[643,1602,1603],{},"Keep made-up URLs and request floods from getting past the cache",[643,1605,1606],{},[702,1607,577],{"href":578},[626,1609,1610,1613],{},[643,1611,1612],{},"See every cache layer and what clears it",[643,1614,1615],{},[702,1616,60],{"href":61},[626,1618,1619,1622],{},[643,1620,1621],{},"Find out how much traffic the site can take",[643,1623,1624],{},[702,1625,581],{"href":582},[626,1627,1628,1631],{},[643,1629,1630],{},"Measure what one visitor experiences",[643,1632,1633],{},[702,1634,585],{"href":586},[626,1636,1637,1640],{},[643,1638,1639],{},"Test the built site in a browser before every deploy",[643,1641,1642],{},[702,1643,593],{"href":594},[626,1645,1646,1649],{},[643,1647,1648],{},"Speed up a slow functional test suite",[643,1650,1651],{},[702,1652,597],{"href":598},[626,1654,1655,1658],{},[643,1656,1657],{},"Fix an error or a symptom",[643,1659,1660],{},[702,1661,601],{"href":602},[626,1663,1664,1667],{},[643,1665,1666],{},"Bring a project up to a newer template release",[643,1668,1669],{},[702,1670,20],{"href":21},[1672,1673,1674],"style",{},"html pre.shiki code .s-h7I, html code.shiki .s-h7I{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#F07178}html pre.shiki code .sOvfz, html code.shiki .sOvfz{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#89DDFF}html pre.shiki code .sLL54, html code.shiki .sLL54{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#C3E88D}html pre.shiki code .sRCss, html code.shiki .sRCss{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#FFCB6B}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 .szhYu, html code.shiki .szhYu{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#C3E88D}html pre.shiki code .sVlFx, html code.shiki .sVlFx{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#89DDFF}html pre.shiki code .seSrl, html code.shiki .seSrl{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#89DDFF}",{"title":864,"searchDepth":886,"depth":886,"links":1676},[1677,1678,1679,1680,1681,1683,1684,1685,1686,1687],{"id":746,"depth":886,"text":747},{"id":1134,"depth":886,"text":1135},{"id":1178,"depth":886,"text":1179},{"id":1213,"depth":886,"text":1214},{"id":1256,"depth":886,"text":1682},"Push main and check staging",{"id":1287,"depth":886,"text":1288},{"id":1302,"depth":886,"text":1303},{"id":1356,"depth":886,"text":1357},{"id":1372,"depth":886,"text":1373},{"id":1511,"depth":886,"text":1512},"Choose between one server with Docker Compose (a preview) and Kubernetes with Helm, then take a new site to production on Kubernetes step by step, with the template's GitLab or GitHub pipeline.","md",{},{"title":539,"description":1688},"DghQo_CX2l3yWgprye8OP5uegoRvwww8x3oOrTuz3SE",[1694,1696],{"title":530,"path":531,"stem":532,"description":1695,"children":-1},"How the module lets a shared cache store rendered page HTML, tags it for purging, and works out how long each page can be kept.",{"title":541,"path":542,"stem":543,"description":1697,"children":-1},"The Docker Compose stack for local development and single-server production (a preview) — services, volumes, environment variables, the images and their build stages, and how Caddy caches pages.",1793565688259]