[{"data":1,"prerenderedAt":3128},["ShallowReactive",2],{"navigation":3,"/docs/image-variations/frankenphp":229,"/docs/image-variations/frankenphp-surround":3123},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","/docs","docs",[9,12,56,85,132,153,186,203,216],{"title":10,"path":6,"stem":11},"","docs/index",{"title":13,"path":14,"stem":15,"children":16,"icon":55},"Getting Started","/docs/getting-started","docs/1.getting-started/1.index",[17,19,23,27,31,35,39,43,47,51],{"title":18,"path":14,"stem":15},"Introduction",{"title":20,"path":21,"stem":22},"Container Basics","/docs/getting-started/container-basics","docs/1.getting-started/2.container-basics",{"title":24,"path":25,"stem":26},"Installation","/docs/getting-started/installation","docs/1.getting-started/3.installation",{"title":28,"path":29,"stem":30},"These Images vs Others","/docs/getting-started/these-images-vs-others","docs/1.getting-started/4.these-images-vs-others",{"title":32,"path":33,"stem":34},"Choosing an Image","/docs/getting-started/choosing-an-image","docs/1.getting-started/5.choosing-an-image",{"title":36,"path":37,"stem":38},"Default Configurations","/docs/getting-started/default-configurations","docs/1.getting-started/6.default-configurations",{"title":40,"path":41,"stem":42},"Upgrade Guide","/docs/getting-started/upgrade-guide","docs/1.getting-started/7.upgrade-guide",{"title":44,"path":45,"stem":46},"Changelog","/docs/getting-started/changelog","docs/1.getting-started/8.changelog",{"title":48,"path":49,"stem":50},"About","/docs/getting-started/about","docs/1.getting-started/9.about",{"title":52,"path":53,"stem":54},"Contributing","/docs/getting-started/contributing","docs/1.getting-started/99.contributing",false,{"title":57,"path":58,"stem":59,"children":60,"page":55},"Image Variations","/docs/image-variations","docs/2.image-variations",[61,65,69,73,77,81],{"title":62,"path":63,"stem":64},"CLI","/docs/image-variations/cli","docs/2.image-variations/cli",{"title":66,"path":67,"stem":68},"FPM","/docs/image-variations/fpm","docs/2.image-variations/fpm",{"title":70,"path":71,"stem":72},"FPM-Apache","/docs/image-variations/fpm-apache","docs/2.image-variations/fpm-apache",{"title":74,"path":75,"stem":76},"FPM-NGINX","/docs/image-variations/fpm-nginx","docs/2.image-variations/fpm-nginx",{"title":78,"path":79,"stem":80},"FrankenPHP","/docs/image-variations/frankenphp","docs/2.image-variations/frankenphp",{"title":82,"path":83,"stem":84},"Unit (Deprecated)","/docs/image-variations/unit","docs/2.image-variations/unit",{"title":86,"path":87,"stem":88,"children":89,"page":55},"Framework Guides","/docs/framework-guides","docs/3.framework-guides",[90,123],{"title":91,"icon":55,"defaultOpen":55,"path":92,"stem":93,"children":94,"page":55},"Laravel","/docs/framework-guides/laravel","docs/3.framework-guides/1.laravel",[95,99,103,107,111,115,119],{"title":96,"path":97,"stem":98},"Automations","/docs/framework-guides/laravel/automations","docs/3.framework-guides/1.laravel/1.automations",{"title":100,"path":101,"stem":102},"Task Scheduler","/docs/framework-guides/laravel/task-scheduler","docs/3.framework-guides/1.laravel/2.task-scheduler",{"title":104,"path":105,"stem":106},"Queue","/docs/framework-guides/laravel/queue","docs/3.framework-guides/1.laravel/3.queue",{"title":108,"path":109,"stem":110},"Horizon","/docs/framework-guides/laravel/horizon","docs/3.framework-guides/1.laravel/4.horizon",{"title":112,"path":113,"stem":114},"Reverb","/docs/framework-guides/laravel/reverb","docs/3.framework-guides/1.laravel/4.reverb",{"title":116,"path":117,"stem":118},"Nightwatch","/docs/framework-guides/laravel/nightwatch","docs/3.framework-guides/1.laravel/5.nightwatch",{"title":120,"path":121,"stem":122},"Octane","/docs/framework-guides/laravel/octane","docs/3.framework-guides/1.laravel/octane",{"title":124,"icon":55,"defaultOpen":55,"path":125,"stem":126,"children":127,"page":55},"WordPress","/docs/framework-guides/wordpress","docs/3.framework-guides/2.wordpress",[128],{"title":129,"path":130,"stem":131},"Using Docker with WordPress","/docs/framework-guides/wordpress/using-wordpress-with-docker","docs/3.framework-guides/2.wordpress/4.using-wordpress-with-docker",{"title":133,"path":134,"stem":135,"children":136,"page":55},"Deployment And Production","/docs/deployment-and-production","docs/4.deployment-and-production",[137,141,145,149],{"title":138,"path":139,"stem":140},"Development to Production","/docs/deployment-and-production/development-to-production","docs/4.deployment-and-production/2.development-to-production",{"title":142,"path":143,"stem":144},"Packaging Your App for Deployment","/docs/deployment-and-production/packaging-your-app-for-deployment","docs/4.deployment-and-production/3.packaging-your-app-for-deployment",{"title":146,"path":147,"stem":148},"Configuring SSL","/docs/deployment-and-production/configuring-ssl","docs/4.deployment-and-production/4.configuring-ssl",{"title":150,"path":151,"stem":152},"Choosing a Host","/docs/deployment-and-production/choosing-a-host","docs/4.deployment-and-production/5.choosing-a-host",{"title":154,"icon":55,"defaultOpen":55,"path":155,"stem":156,"children":157,"page":55},"Advanced Guides","/docs/guide","docs/5.guide",[158,162,166,170,174,178,182],{"title":159,"path":160,"stem":161},"Migrating from official PHP images","/docs/guide/migrating-from-official-php-images","docs/5.guide/1.migrating-from-official-php-images",{"title":163,"path":164,"stem":165},"Using Healthchecks With Laravel","/docs/guide/using-healthchecks-with-laravel","docs/5.guide/2.using-healthchecks-with-laravel",{"title":167,"path":168,"stem":169},"Using S6 Overlay","/docs/guide/using-s6-overlay","docs/5.guide/2.using-s6-overlay",{"title":171,"path":172,"stem":173},"Understanding File Permissions","/docs/guide/understanding-file-permissions","docs/5.guide/3.understanding-file-permissions",{"title":175,"path":176,"stem":177},"Configuring Trusted Proxies","/docs/guide/configuring-trusted-proxies","docs/5.guide/4.configuring-trusted-proxies",{"title":179,"path":180,"stem":181},"Major version migrations","/docs/guide/major-version-migrations","docs/5.guide/5.major-version-migrations",{"title":183,"path":184,"stem":185},"Production performance tuning","/docs/guide/production-performance-tuning","docs/5.guide/6.production-performance-tuning",{"title":187,"icon":55,"defaultOpen":55,"path":188,"stem":189,"children":190,"page":55},"Customization","/docs/customizing-the-image","docs/6.customizing-the-image",[191,195,199],{"title":192,"path":193,"stem":194},"Changing php.ini settings","/docs/customizing-the-image/changing-common-php-settings","docs/6.customizing-the-image/1.changing-common-php-settings",{"title":196,"path":197,"stem":198},"Installing PHP extensions","/docs/customizing-the-image/installing-additional-php-extensions","docs/6.customizing-the-image/2.installing-additional-php-extensions",{"title":200,"path":201,"stem":202},"Adding Start Up Scripts","/docs/customizing-the-image/adding-your-own-start-up-scripts","docs/6.customizing-the-image/3.adding-your-own-start-up-scripts",{"title":204,"path":205,"stem":206,"children":207,"page":55},"Troubleshooting","/docs/troubleshooting","docs/7.troubleshooting",[208,212],{"title":209,"path":210,"stem":211},"Common Issues","/docs/troubleshooting/common-issues","docs/7.troubleshooting/1.common-issues",{"title":213,"path":214,"stem":215},"Getting Help","/docs/troubleshooting/getting-help","docs/7.troubleshooting/2.getting-help",{"title":217,"path":218,"stem":219,"children":220,"page":55},"Reference","/docs/reference","docs/8.reference",[221,225],{"title":222,"path":223,"stem":224},"Environment Variable Specification","/docs/reference/environment-variable-specification","docs/8.reference/1.environment-variable-specification",{"title":226,"path":227,"stem":228},"Command Reference","/docs/reference/command-reference","docs/8.reference/2.command-reference",{"id":230,"title":78,"body":231,"description":3118,"extension":486,"links":3119,"meta":3120,"navigation":2793,"path":79,"redirect":3119,"seo":3121,"stem":80,"__hash__":3122},"docs/docs/2.image-variations/frankenphp.md",{"type":232,"value":233,"toc":3084},"minimark",[234,244,249,252,274,279,302,306,427,439,445,449,466,472,490,494,497,502,509,515,537,546,550,553,558,584,653,662,666,669,674,712,716,719,724,738,746,755,759,762,767,801,804,809,813,816,821,835,838,842,998,1002,1005,1009,1023,1027,1030,1043,1046,1051,1055,1089,1093,1096,1100,1141,1151,1155,1158,1167,1310,1315,1318,1329,1333,1337,1340,1350,1356,1360,1363,1366,1374,1378,1475,1482,1498,1502,1508,1577,1580,1597,1603,1607,1611,1634,1658,1664,1707,1729,1742,1760,1774,1778,1789,1883,1897,2028,2034,2065,2090,2094,2097,2101,2376,2384,2388,2548,2552,2555,2559,2572,2663,2679,2682,2740,2747,2840,2844,2851,2869,2872,2936,2953,2995,2999,3006,3026,3035,3039,3045,3049,3052,3080],[235,236,237,241],"lead-p",{},[238,239,240],"p",{},"The FrankenPHP variation is a modern application server built on top of the Caddy web server. It runs PHP and the web server in a single process, eliminating the complexity of managing PHP-FPM and a separate web server.",[238,242,243],{},"This is the cutting-edge variation that offers worker mode, automatic HTTPS, and modern protocols like HTTP/2 and HTTP/3. It's the recommended variation for new Laravel projects seeking maximum performance.",[245,246,248],"h2",{"id":247},"when-to-use-frankenphp","When to Use FrankenPHP",[238,250,251],{},"Use the FrankenPHP variation when you need to:",[253,254,255,259,262,265,268,271],"ul",{},[256,257,258],"li",{},"Run Laravel Octane with maximum performance",[256,260,261],{},"Use worker mode to keep your application in memory",[256,263,264],{},"Get automatic HTTPS with zero configuration",[256,266,267],{},"Support modern protocols like HTTP/2 and HTTP/3",[256,269,270],{},"Simplify your container architecture (single process)",[256,272,273],{},"Deploy Symfony applications with the Runtime component",[275,276,278],"h4",{"id":277},"perfect-for","Perfect for",[253,280,281,284,287,290,293,296,299],{},[256,282,283],{},"Laravel Octane applications",[256,285,286],{},"Symfony applications using the Runtime component",[256,288,289],{},"Modern PHP applications that can benefit from worker mode",[256,291,292],{},"Projects requiring automatic HTTPS",[256,294,295],{},"High-performance APIs that benefit from persistent connections",[256,297,298],{},"Teams wanting the latest and greatest in PHP application servers",[256,300,301],{},"Apps that need PHP 8.3 or newer",[245,303,305],{"id":304},"comparing-frankenphp-to-other-variations","Comparing FrankenPHP to Other Variations",[307,308,309,325],"table",{},[310,311,312],"thead",{},[313,314,315,319,321,323],"tr",{},[316,317,318],"th",{},"Feature",[316,320,78],{},[316,322,74],{},[316,324,70],{},[326,327,328,343,355,368,379,390,403,414],"tbody",{},[313,329,330,334,337,340],{},[331,332,333],"td",{},"Performance",[331,335,336],{},"⚡️ Excellent (worker mode)",[331,338,339],{},"✅ Very Good",[331,341,342],{},"✅ Good",[313,344,345,348,351,353],{},[331,346,347],{},"Setup Complexity",[331,349,350],{},"✅ Simple",[331,352,350],{},[331,354,350],{},[313,356,357,360,363,366],{},[331,358,359],{},"Worker Mode",[331,361,362],{},"✅ Yes",[331,364,365],{},"❌ No",[331,367,365],{},[313,369,370,373,375,377],{},[331,371,372],{},"Automatic HTTPS",[331,374,362],{},[331,376,365],{},[331,378,365],{},[313,380,381,384,386,388],{},[331,382,383],{},"HTTP/3 Support",[331,385,362],{},[331,387,365],{},[331,389,365],{},[313,391,392,395,398,401],{},[331,393,394],{},"Laravel Octane",[331,396,397],{},"✅ Native support",[331,399,400],{},"❌ Not supported",[331,402,400],{},[313,404,405,408,410,412],{},[331,406,407],{},".htaccess Support",[331,409,365],{},[331,411,365],{},[331,413,362],{},[313,415,416,419,422,425],{},[331,417,418],{},"Maturity",[331,420,421],{},"⚠️ New",[331,423,424],{},"✅ Mature",[331,426,424],{},[238,428,429,430,433,434,438],{},"Octane replaces PHP-FPM, so it cannot run inside the FPM variations at all. The NGINX and Apache in those images are PHP-FPM front ends, not reverse proxies. If you want Octane without FrankenPHP, run Octane's Swoole or RoadRunner server from our ",[431,432,62],"a",{"href":63}," image instead. See ",[431,435,437],{"href":436},"/docs/framework-guides/laravel/octane#running-octane-without-frankenphp","Running Octane Without FrankenPHP",".",[440,441,442],"tip",{},[238,443,444],{},"FrankenPHP is the newest variation and represents the future of PHP application servers. If you're starting a new project and can commit to modern practices, this is the variation to choose.",[275,446,448],{"id":447},"known-issues","Known Issues",[450,451,454],"warning",{"target":452,"to":453},"_blank","https://frankenphp.dev/docs/known-issues/#standalone-binary-and-alpine-based-docker-images",[238,455,456,457,461,462,465],{},"Some people are reporting performance issues on the ",[458,459,460],"code",{},"alpine"," version of FrankenPHP. If you're experiencing this, consider using the ",[458,463,464],{},"debian"," version.",[238,467,468,469,471],{},"FrankenPHP is cutting edge and is a very active project. Be sure to understand FrankenPHP's known issues before using it in production. If you're looking for better compatibility, consider using the ",[431,470,74],{"href":75}," image.",[473,474],"u-button",{"ariaLabel":475,"className":476,"color":484,"label":485,"size":486,"to":487,"trailing-icon":488,"variant":489,"target":452},"FrankenPHP known issues",[477,478,479,480,481,482,483],"font-bold","ring","ring-inset","ring-blue-600","text-blue-600","hover:ring-blue-500","hover:text-blue-500","primary","View FrankenPHP's known issues","md","https://frankenphp.dev/docs/known-issues/","i-lucide-arrow-right","outline",[245,491,493],{"id":492},"differences-from-official-frankenphp-images","Differences from Official FrankenPHP Images",[238,495,496],{},"Our FrankenPHP images are built with production deployments and enterprise security in mind. While the official FrankenPHP images are great for getting started, we've made several enhancements that make these images more suitable for production environments, especially when deploying at scale with orchestrators like Kubernetes, Docker Swarm, or managed container platforms.",[498,499,501],"h3",{"id":500},"security-first-design-unprivileged-by-default","Security-First Design: Unprivileged by Default",[238,503,504,505,508],{},"Unlike the official FrankenPHP images that run as root, our images run as the unprivileged ",[458,506,507],{},"www-data"," user by default. This dramatically reduces your security footprint in production environments.",[238,510,511],{},[512,513,514],"strong",{},"What this means for you:",[253,516,517,520,527,534],{},[256,518,519],{},"Containers run with minimal privileges, following security best practices",[256,521,522,523,526],{},"HTTP listens on port ",[458,524,525],{},"8080"," (instead of 80)",[256,528,529,530,533],{},"HTTPS listens on port ",[458,531,532],{},"8443"," (instead of 443)",[256,535,536],{},"Consistent with our other image variations for a unified experience",[440,538,539],{},[238,540,541,542,438],{},"This unprivileged design is consistent across all our image variations. Learn more about our ",[431,543,545],{"href":544},"/docs/getting-started/default-configurations#unprivileged-by-default","default configurations",[498,547,549],{"id":548},"native-health-checks-with-laravel-integration","Native Health Checks with Laravel Integration",[238,551,552],{},"Health checks are critical for zero-downtime deployments, but the official images don't include them. Our images come with intelligent health check endpoints that work out of the box.",[238,554,555],{},[512,556,557],{},"Built-in features:",[253,559,560,567,574,581],{},[256,561,562,563,566],{},"Default ",[458,564,565],{},"/healthcheck"," endpoint configured in Caddy",[256,568,569,570,573],{},"Configurable via ",[458,571,572],{},"HEALTHCHECK_PATH"," environment variable",[256,575,576,577,580],{},"Works with Laravel's native ",[458,578,579],{},"/up"," health check endpoint",[256,582,583],{},"Ensures your application is truly ready before accepting traffic",[585,586,591],"pre",{"className":587,"code":588,"filename":589,"language":590,"meta":10,"style":10},"language-yml shiki shiki-themes github-dark","services:\n  php:\n    image: serversideup/php:8.5-frankenphp\n    environment:\n      # Use Laravel's built-in health check\n      HEALTHCHECK_PATH: /up\n","compose.yml","yml",[458,592,593,606,614,627,635,642],{"__ignoreMap":10},[594,595,598,602],"span",{"class":596,"line":597},"line",1,[594,599,601],{"class":600},"s4JwU","services",[594,603,605],{"class":604},"s95oV",":\n",[594,607,609,612],{"class":596,"line":608},2,[594,610,611],{"class":600},"  php",[594,613,605],{"class":604},[594,615,617,620,623],{"class":596,"line":616},3,[594,618,619],{"class":600},"    image",[594,621,622],{"class":604},": ",[594,624,626],{"class":625},"sU2Wk","serversideup/php:8.5-frankenphp\n",[594,628,630,633],{"class":596,"line":629},4,[594,631,632],{"class":600},"    environment",[594,634,605],{"class":604},[594,636,638],{"class":596,"line":637},5,[594,639,641],{"class":640},"sAwPA","      # Use Laravel's built-in health check\n",[594,643,645,648,650],{"class":596,"line":644},6,[594,646,647],{"class":600},"      HEALTHCHECK_PATH",[594,649,622],{"class":604},[594,651,652],{"class":625},"/up\n",[440,654,655],{},[238,656,657,658,661],{},"Learn more about ",[431,659,660],{"href":164},"using health checks with Laravel"," to ensure your application is ready before accepting requests.",[498,663,665],{"id":664},"production-grade-caddyfile-configuration","Production-Grade Caddyfile Configuration",[238,667,668],{},"The official FrankenPHP Dockerfile provides a basic Caddyfile to get started. We've spent considerable time crafting a production-ready configuration that includes security hardening, performance optimizations, and enterprise features.",[238,670,671],{},[512,672,673],{},"What's included:",[253,675,676,682,688,694,700,706],{},[256,677,678,681],{},[512,679,680],{},"CloudFlare integration"," - Trusted IP addresses configured automatically",[256,683,684,687],{},[512,685,686],{},"Security headers"," - Best-practice headers included by default",[256,689,690,693],{},[512,691,692],{},"Performance rules"," - Smart caching and compression configured",[256,695,696,699],{},[512,697,698],{},"Flexible logging"," - Configurable output formats and levels",[256,701,702,705],{},[512,703,704],{},"Self-signed certificates"," - Automatic generation for development environments",[256,707,708,711],{},[512,709,710],{},"Let's Encrypt support"," - Easy configuration for automatic SSL certificates",[498,713,715],{"id":714},"designed-for-orchestrator-deployments","Designed for Orchestrator Deployments",[238,717,718],{},"FrankenPHP's tight integration with Caddy enables amazing features like automatic Let's Encrypt SSL certificates. However, in most production deployments, you're likely using a load balancer or reverse proxy for SSL termination, making Caddy's automatic SSL less useful and potentially problematic at scale.",[238,720,721],{},[512,722,723],{},"Our orchestrator-first approach:",[253,725,726,729,732,735],{},[256,727,728],{},"Assumes SSL/TLS termination happens at the load balancer level",[256,730,731],{},"Optimized for zero-downtime rolling deployments",[256,733,734],{},"Works seamlessly with Kubernetes, Docker Swarm, and managed platforms",[256,736,737],{},"Simplifies scaling from one container to hundreds",[238,739,740],{},[741,742],"img",{":zoom":743,"alt":744,"src":745},"false","Reverse Proxy","images/docs/reverse-proxy-ssl-zerodowntime.png",[747,748,749],"note",{},[238,750,751,752,754],{},"You can still use Caddy's automatic HTTPS with Let's Encrypt if you prefer. See our ",[431,753,146],{"href":147}," guide for all available options.",[498,756,758],{"id":757},"consistent-environment-variable-experience","Consistent Environment Variable Experience",[238,760,761],{},"Just like all our other PHP variations, the FrankenPHP images support the same environment variables and helper scripts you're already familiar with.",[238,763,764],{},[512,765,766],{},"Unified configuration across all variations:",[253,768,769,786,792,795,798],{},[256,770,771,774,775,778,779,778,782,785],{},[458,772,773],{},"SSL_MODE"," - Control SSL behavior (",[458,776,777],{},"off",", ",[458,780,781],{},"mixed",[458,783,784],{},"full",")",[256,787,788,791],{},[458,789,790],{},"LOG_OUTPUT_LEVEL"," - Adjust logging verbosity",[256,793,794],{},"PHP INI settings via environment variables",[256,796,797],{},"Helper scripts for permissions management",[256,799,800],{},"Consistent startup script behavior",[238,802,803],{},"This means you can switch between variations (FrankenPHP, FPM-NGINX, FPM-Apache) with minimal configuration changes.",[473,805],{"ariaLabel":806,"className":807,"color":484,"label":808,"size":486,"to":223,"trailing-icon":488,"variant":489},"View environment variable specification",[477,478,479,480,481,482,483],"View all environment variables",[498,810,812],{"id":811},"more-operating-system-variations","More Operating System Variations",[238,814,815],{},"We compile FrankenPHP from source, which allows us to support multiple operating systems for maximum flexibility.",[238,817,818],{},[512,819,820],{},"Available platforms:",[253,822,823,826,829,832],{},[256,824,825],{},"Debian Bookworm (12)",[256,827,828],{},"Debian Trixie (13)",[256,830,831],{},"Alpine 3.23",[256,833,834],{},"Alpine 3.24",[238,836,837],{},"This gives you the freedom to choose the base OS that best fits your infrastructure and security requirements.",[275,839,841],{"id":840},"whats-inside","What's Inside",[307,843,844,854],{},[310,845,846],{},[313,847,848,851],{},[316,849,850],{},"Item",[316,852,853],{},"Status",[326,855,856,864,872,879,886,896,906,913,920,926,933,940,947,955,963,971,988],{},[313,857,858,861],{},[331,859,860],{},"FrankenPHP application server",[331,862,863],{},"✅",[313,865,866,869],{},[331,867,868],{},"Caddy web server",[331,870,871],{},"✅ (built-in)",[313,873,874,877],{},[331,875,876],{},"PHP CLI binary",[331,878,863],{},[313,880,881,884],{},[331,882,883],{},"Common PHP extensions",[331,885,863],{},[313,887,888,894],{},[331,889,890,893],{},[458,891,892],{},"composer"," executable",[331,895,863],{},[313,897,898,904],{},[331,899,900,903],{},[458,901,902],{},"install-php-extensions"," script",[331,905,863],{},[313,907,908,911],{},[331,909,910],{},"Essential system utilities",[331,912,863],{},[313,914,915,918],{},[331,916,917],{},"Worker mode support",[331,919,863],{},[313,921,922,924],{},[331,923,372],{},[331,925,863],{},[313,927,928,931],{},[331,929,930],{},"HTTP/2 support",[331,932,863],{},[313,934,935,938],{},[331,936,937],{},"HTTP/3 support",[331,939,863],{},[313,941,942,945],{},[331,943,944],{},"Mercure (real-time)",[331,946,863],{},[313,948,949,952],{},[331,950,951],{},"Native health checks",[331,953,954],{},"✅ (via HTTP endpoint)",[313,956,957,960],{},[331,958,959],{},"SSL/TLS support",[331,961,962],{},"✅ (automatic + self-signed)",[313,964,965,968],{},[331,966,967],{},"Process management",[331,969,970],{},"Single process (no supervisor needed)",[313,972,973,976],{},[331,974,975],{},"Exposed Ports",[331,977,978,980,981,983,984,987],{},[458,979,525],{}," (HTTP), ",[458,982,532],{}," (HTTPS + HTTP/3), ",[458,985,986],{},"2019"," (Caddy admin)",[313,989,990,993],{},[331,991,992],{},"Stop Signal",[331,994,995],{},[458,996,997],{},"SIGTERM",[245,999,1001],{"id":1000},"classic-mode-vs-worker-mode","Classic Mode vs Worker Mode",[238,1003,1004],{},"Unlike traditional setups that require a separate web server and PHP-FPM, FrankenPHP runs everything in a single process. It also operates in two modes:",[275,1006,1008],{"id":1007},"classic-mode-default","Classic Mode (Default)",[253,1010,1011,1014,1017,1020],{},[256,1012,1013],{},"FrankenPHP functions like a traditional PHP server (similar to PHP-FPM)",[256,1015,1016],{},"Each request bootstraps your application fresh",[256,1018,1019],{},"No additional configuration needed",[256,1021,1022],{},"Safe for any existing PHP applications",[275,1024,1026],{"id":1025},"worker-mode-advanced","Worker Mode (Advanced)",[238,1028,1029],{},"Worker mode is FrankenPHP's killer feature. Instead of bootstrapping your application for every request, it stays loaded in memory:",[253,1031,1032,1038],{},[256,1033,1034,1037],{},[512,1035,1036],{},"Traditional",": Bootstrap app → Handle request → Teardown → Repeat",[256,1039,1040,1042],{},[512,1041,359],{},": Bootstrap app once → Handle requests indefinitely",[238,1044,1045],{},"This can result in dramatic performance improvements for Laravel applications.",[440,1047,1048],{},[238,1049,1050],{},"Worker mode is perfect for Laravel Octane. Your application boots once and handles thousands of requests without reloading, dramatically improving response times.",[245,1052,1054],{"id":1053},"how-frankenphp-works","How FrankenPHP Works",[1056,1057,1059,1063,1066,1070,1073,1082,1086],"steps",{"level":1058},"4",[275,1060,1062],{"id":1061},"client-sends-request","Client sends request",[238,1064,1065],{},"The client sends an HTTP request to port 8080 (or 8443 for HTTPS).",[275,1067,1069],{"id":1068},"frankenphp-receives-and-processes-the-request","FrankenPHP receives and processes the request",[238,1071,1072],{},"FrankenPHP receives and processes the request directly in a single process. This includes:",[1074,1075,1076,1079],"ol",{},[256,1077,1078],{},"Static files",[256,1080,1081],{},"PHP requests",[275,1083,1085],{"id":1084},"send-response-back-to-client","Send response back to client",[238,1087,1088],{},"The response is sent back to the client.",[245,1090,1092],{"id":1091},"quick-start","Quick Start",[238,1094,1095],{},"Here are a few examples to help you get started with the FrankenPHP variation.",[498,1097,1099],{"id":1098},"docker-cli","Docker CLI",[585,1101,1106],{"className":1102,"code":1103,"filename":1104,"language":1105,"meta":10,"style":10},"language-bash shiki shiki-themes github-dark","docker run -p 80:8080 -v $(pwd):/var/www/html/public serversideup/php:8.5-frankenphp\n","Terminal","bash",[458,1107,1108],{"__ignoreMap":10},[594,1109,1110,1114,1117,1121,1124,1127,1130,1133,1135,1138],{"class":596,"line":597},[594,1111,1113],{"class":1112},"svObZ","docker",[594,1115,1116],{"class":625}," run",[594,1118,1120],{"class":1119},"sDLfK"," -p",[594,1122,1123],{"class":625}," 80:8080",[594,1125,1126],{"class":1119}," -v",[594,1128,1129],{"class":604}," $(",[594,1131,1132],{"class":1119},"pwd",[594,1134,785],{"class":604},[594,1136,1137],{"class":625},":/var/www/html/public",[594,1139,1140],{"class":625}," serversideup/php:8.5-frankenphp\n",[238,1142,1143,1144,1147,1148,438],{},"Your application will be available at ",[458,1145,1146],{},"http://localhost",". The default webroot is ",[458,1149,1150],{},"/var/www/html/public",[498,1152,1154],{"id":1153},"docker-compose","Docker Compose",[238,1156,1157],{},"Here's a basic example getting FrankenPHP up and running with Docker Compose.",[450,1159,1160],{},[238,1161,1162,1163,1166],{},"Don't forget to create a ",[458,1164,1165],{},"public"," directory and put your PHP code in there.",[1168,1169,1170,1275],"code-tree",{"default-value":589},[585,1171,1173],{"className":587,"code":1172,"filename":589,"language":590,"meta":10,"style":10},"services:\n  php:\n    # Choose our PHP version and variation\n    image: serversideup/php:8.5-frankenphp\n    # Expose and map HTTP and HTTPS ports\n    ports:\n      - 80:8080\n      - 443:8443\n    # Mount current directory to /var/www/html\n    volumes:\n      - ./:/var/www/html\n    # Support both HTTP and HTTPS\n    environment:\n      SSL_MODE: mixed\n",[458,1174,1175,1181,1187,1192,1200,1205,1212,1221,1229,1235,1243,1251,1257,1264],{"__ignoreMap":10},[594,1176,1177,1179],{"class":596,"line":597},[594,1178,601],{"class":600},[594,1180,605],{"class":604},[594,1182,1183,1185],{"class":596,"line":608},[594,1184,611],{"class":600},[594,1186,605],{"class":604},[594,1188,1189],{"class":596,"line":616},[594,1190,1191],{"class":640},"    # Choose our PHP version and variation\n",[594,1193,1194,1196,1198],{"class":596,"line":629},[594,1195,619],{"class":600},[594,1197,622],{"class":604},[594,1199,626],{"class":625},[594,1201,1202],{"class":596,"line":637},[594,1203,1204],{"class":640},"    # Expose and map HTTP and HTTPS ports\n",[594,1206,1207,1210],{"class":596,"line":644},[594,1208,1209],{"class":600},"    ports",[594,1211,605],{"class":604},[594,1213,1215,1218],{"class":596,"line":1214},7,[594,1216,1217],{"class":604},"      - ",[594,1219,1220],{"class":625},"80:8080\n",[594,1222,1224,1226],{"class":596,"line":1223},8,[594,1225,1217],{"class":604},[594,1227,1228],{"class":625},"443:8443\n",[594,1230,1232],{"class":596,"line":1231},9,[594,1233,1234],{"class":640},"    # Mount current directory to /var/www/html\n",[594,1236,1238,1241],{"class":596,"line":1237},10,[594,1239,1240],{"class":600},"    volumes",[594,1242,605],{"class":604},[594,1244,1246,1248],{"class":596,"line":1245},11,[594,1247,1217],{"class":604},[594,1249,1250],{"class":625},"./:/var/www/html\n",[594,1252,1254],{"class":596,"line":1253},12,[594,1255,1256],{"class":640},"    # Support both HTTP and HTTPS\n",[594,1258,1260,1262],{"class":596,"line":1259},13,[594,1261,632],{"class":600},[594,1263,605],{"class":604},[594,1265,1267,1270,1272],{"class":596,"line":1266},14,[594,1268,1269],{"class":600},"      SSL_MODE",[594,1271,622],{"class":604},[594,1273,1274],{"class":625},"mixed\n",[585,1276,1281],{"className":1277,"code":1278,"filename":1279,"language":1280,"meta":10,"style":10},"language-php shiki shiki-themes github-dark","\u003C?php\n// Let's just print out some PHP info\nphpinfo();\n?>\n","public/index.php","php",[458,1282,1283,1292,1297,1305],{"__ignoreMap":10},[594,1284,1285,1289],{"class":596,"line":597},[594,1286,1288],{"class":1287},"snl16","\u003C?",[594,1290,1291],{"class":1119},"php\n",[594,1293,1294],{"class":596,"line":608},[594,1295,1296],{"class":640},"// Let's just print out some PHP info\n",[594,1298,1299,1302],{"class":596,"line":616},[594,1300,1301],{"class":1119},"phpinfo",[594,1303,1304],{"class":604},"();\n",[594,1306,1307],{"class":596,"line":629},[594,1308,1309],{"class":1287},"?>\n",[440,1311,1312],{},[238,1313,1314],{},"The FrankenPHP variation uses ports 8080 and 8443 (instead of 80 and 443) to allow the container to run as a non-root user for better security.",[498,1316,394],{"id":1317},"laravel-octane",[238,1319,1320,1321,1324,1325,1328],{},"Laravel Octane natively supports FrankenPHP. Pass ",[458,1322,1323],{},"--caddyfile=/etc/frankenphp/Caddyfile"," to ",[458,1326,1327],{},"octane:start"," and our Caddyfile switches into worker mode while keeping the same production configuration as classic mode. Use our guide below to learn more.",[473,1330],{"ariaLabel":1331,"className":1332,"color":484,"label":1331,"size":486,"to":121,"trailing-icon":488,"variant":489},"Learn more about Laravel Octane",[477,478,479,480,481,482,483],[498,1334,1336],{"id":1335},"health-check","Health Check",[238,1338,1339],{},"The FrankenPHP variation includes a built-in health check that verifies the server is responding:",[747,1341,1342],{},[238,1343,1344,1345,1347,1348,438],{},"The health check endpoint is configurable via the ",[458,1346,572],{}," environment variable, which defaults to ",[458,1349,565],{},[238,1351,1352,1353,1355],{},"If you are using Laravel, you can use the ",[458,1354,579],{}," route to validate that Laravel is running and healthy.",[473,1357],{"ariaLabel":1358,"className":1359,"color":484,"label":1358,"size":486,"to":164,"trailing-icon":488,"variant":489},"Learn more about using healthchecks with Laravel",[477,478,479,480,481,482,483],[245,1361,372],{"id":1362},"automatic-https",[238,1364,1365],{},"One of FrankenPHP's standout features is automatic HTTPS powered by Caddy. It can automatically obtain and renew SSL certificates from Let's Encrypt.",[440,1367,1368],{"to":147},[238,1369,1370,1371,1373],{},"See our ",[431,1372,146],{"href":147}," guide for more information on the best strategies for running SSL in production.",[498,1375,1377],{"id":1376},"enabling-automatic-https","Enabling Automatic HTTPS",[585,1379,1381],{"className":587,"code":1380,"filename":589,"language":590,"meta":10,"style":10},"services:\n  php:\n    image: serversideup/php:8.5-frankenphp\n    ports:\n      - \"80:8080\"\n      - \"443:8443\"\n    volumes:\n      - ./:/var/www/html\n    environment:\n      CADDY_AUTO_HTTPS: \"on\"\n      # Your domain for automatic certificate\n      SERVER_NAME: \"example.com\"\n      SSL_MODE: \"full\"\n",[458,1382,1383,1389,1395,1403,1409,1416,1423,1429,1435,1441,1451,1456,1466],{"__ignoreMap":10},[594,1384,1385,1387],{"class":596,"line":597},[594,1386,601],{"class":600},[594,1388,605],{"class":604},[594,1390,1391,1393],{"class":596,"line":608},[594,1392,611],{"class":600},[594,1394,605],{"class":604},[594,1396,1397,1399,1401],{"class":596,"line":616},[594,1398,619],{"class":600},[594,1400,622],{"class":604},[594,1402,626],{"class":625},[594,1404,1405,1407],{"class":596,"line":629},[594,1406,1209],{"class":600},[594,1408,605],{"class":604},[594,1410,1411,1413],{"class":596,"line":637},[594,1412,1217],{"class":604},[594,1414,1415],{"class":625},"\"80:8080\"\n",[594,1417,1418,1420],{"class":596,"line":644},[594,1419,1217],{"class":604},[594,1421,1422],{"class":625},"\"443:8443\"\n",[594,1424,1425,1427],{"class":596,"line":1214},[594,1426,1240],{"class":600},[594,1428,605],{"class":604},[594,1430,1431,1433],{"class":596,"line":1223},[594,1432,1217],{"class":604},[594,1434,1250],{"class":625},[594,1436,1437,1439],{"class":596,"line":1231},[594,1438,632],{"class":600},[594,1440,605],{"class":604},[594,1442,1443,1446,1448],{"class":596,"line":1237},[594,1444,1445],{"class":600},"      CADDY_AUTO_HTTPS",[594,1447,622],{"class":604},[594,1449,1450],{"class":625},"\"on\"\n",[594,1452,1453],{"class":596,"line":1245},[594,1454,1455],{"class":640},"      # Your domain for automatic certificate\n",[594,1457,1458,1461,1463],{"class":596,"line":1253},[594,1459,1460],{"class":600},"      SERVER_NAME",[594,1462,622],{"class":604},[594,1464,1465],{"class":625},"\"example.com\"\n",[594,1467,1468,1470,1472],{"class":596,"line":1259},[594,1469,1269],{"class":600},[594,1471,622],{"class":604},[594,1473,1474],{"class":625},"\"full\"\n",[450,1476,1477],{},[238,1478,1479,1480,438],{},"Automatic HTTPS requires a public domain name and ports 80/443 accessible from the internet for Let's Encrypt validation. For local development, use self-signed certificates with ",[458,1481,773],{},[238,1483,1484,1485,1488,1489,1493,1494,1497],{},"Need Let's Encrypt short-lived certificates or IP-address certificates? Set ",[458,1486,1487],{},"CADDY_ACME_PROFILE: \"shortlived\"",". See ",[431,1490,1492],{"href":1491},"/docs/deployment-and-production/configuring-ssl#short-lived--ip-address-certificates","Short-lived & IP-address certificates"," for the trade-offs and the ",[458,1495,1496],{},"default_sni"," setup for SNI-less access.",[498,1499,1501],{"id":1500},"ssl-modes-for-development","SSL Modes for Development",[238,1503,1504,1505,1507],{},"For local development, use the ",[458,1506,773],{}," environment variable:",[585,1509,1511],{"className":587,"code":1510,"filename":589,"language":590,"meta":10,"style":10},"services:\n  php:\n    image: serversideup/php:8.5-frankenphp\n    ports:\n      - \"80:8080\"\n      - \"443:8443\"\n    volumes:\n      - ./:/var/www/html\n    environment:\n      SSL_MODE: \"full\"\n",[458,1512,1513,1519,1525,1533,1539,1545,1551,1557,1563,1569],{"__ignoreMap":10},[594,1514,1515,1517],{"class":596,"line":597},[594,1516,601],{"class":600},[594,1518,605],{"class":604},[594,1520,1521,1523],{"class":596,"line":608},[594,1522,611],{"class":600},[594,1524,605],{"class":604},[594,1526,1527,1529,1531],{"class":596,"line":616},[594,1528,619],{"class":600},[594,1530,622],{"class":604},[594,1532,626],{"class":625},[594,1534,1535,1537],{"class":596,"line":629},[594,1536,1209],{"class":600},[594,1538,605],{"class":604},[594,1540,1541,1543],{"class":596,"line":637},[594,1542,1217],{"class":604},[594,1544,1415],{"class":625},[594,1546,1547,1549],{"class":596,"line":644},[594,1548,1217],{"class":604},[594,1550,1422],{"class":625},[594,1552,1553,1555],{"class":596,"line":1214},[594,1554,1240],{"class":600},[594,1556,605],{"class":604},[594,1558,1559,1561],{"class":596,"line":1223},[594,1560,1217],{"class":604},[594,1562,1250],{"class":625},[594,1564,1565,1567],{"class":596,"line":1231},[594,1566,632],{"class":600},[594,1568,605],{"class":604},[594,1570,1571,1573,1575],{"class":596,"line":1237},[594,1572,1269],{"class":600},[594,1574,622],{"class":604},[594,1576,1474],{"class":625},[238,1578,1579],{},"Available SSL modes:",[253,1581,1582,1587,1592],{},[256,1583,1584,1586],{},[458,1585,777],{}," - SSL disabled (default)",[256,1588,1589,1591],{},[458,1590,781],{}," - Both HTTP (8080) and HTTPS (8443) enabled",[256,1593,1594,1596],{},[458,1595,784],{}," - HTTPS only on port 8443",[238,1598,1599,1600,1602],{},"Learn more about SSL modes in the ",[431,1601,146],{"href":147}," guide.",[473,1604],{"ariaLabel":1605,"className":1606,"color":484,"label":1605,"size":486,"to":147,"trailing-icon":488,"variant":489},"Learn more about SSL modes",[477,478,479,480,481,482,483],[245,1608,1610],{"id":1609},"logging","Logging",[238,1612,1613,1614,1620,1621,1626,1627,1630,1631,438],{},"FrankenPHP is built on Caddy, and Caddy handles logs differently from NGINX and Apache. Caddy does have an ",[431,1615,1619],{"href":1616,"rel":1617,"target":452},"https://caddyserver.com/docs/caddyfile/directives/log",[1618],"nofollow","access log",", but it is a named logger that shares the same ",[431,1622,1625],{"href":1623,"rel":1624,"target":452},"https://caddyserver.com/docs/logging",[1618],"structured format"," and default output as Caddy's runtime log. Every entry carries its own level: requests are logged at ",[458,1628,1629],{},"INFO"," and problems at ",[458,1632,1633],{},"ERROR",[238,1635,1636,1637,1640,1641,1646,1647,1650,1651,1653,1654],{},"Because both logs share one format and one default output, the FrankenPHP variation sends everything to ",[458,1638,1639],{},"stderr",". That is ",[431,1642,1645],{"href":1643,"rel":1644,"target":452},"https://caddyserver.com/docs/caddyfile/directives/log#output",[1618],"Caddy's default",", it is what the official FrankenPHP image does, and it is what Laravel Octane expects. Our NGINX and Apache variations keep the traditional split of access logs on ",[458,1648,1649],{},"stdout"," and error logs on ",[458,1652,1639],{},", because that is what the official images for those servers do. ",[431,1655,1657],{"href":1656},"/docs/getting-started/default-configurations#logging","Read how we approach logging across all variations →",[238,1659,1660,1663],{},[458,1661,1662],{},"docker logs",", Docker Compose, and Kubernetes capture both streams, so nothing changes in day-to-day use.",[238,1665,1666,1667,1679,1680,1683,1684,1694,1695,1698,1699,1702,1703,1706],{},"The format follows Caddy's default as well. Caddy ",[431,1668,1671,1672,1675,1676,1678],{"href":1669,"rel":1670,"target":452},"https://caddyserver.com/docs/caddyfile/directives/log#format",[1618],"writes human-readable ",[458,1673,1674],{},"console"," lines when ",[458,1677,1639],{}," is an interactive terminal and JSON otherwise",". A container started by Docker Compose, Docker Swarm, or Kubernetes has no terminal, so it gets one JSON object per line. That is what log collectors expect, and every entry carries a ",[458,1681,1682],{},"level"," field your log pipeline can map to a severity instead of guessing from the stream (for example, ",[431,1685,1688,1689,1691,1692],{"href":1686,"rel":1687,"target":452},"https://docs.cloud.google.com/kubernetes-engine/docs/concepts/about-logs",[1618],"GKE tags ",[458,1690,1639],{}," as ",[458,1693,1633],{}," unless it can read a severity). ",[458,1696,1697],{},"docker run -it"," and ",[458,1700,1701],{},"tty: true"," give you the console lines instead. Set ",[458,1704,1705],{},"CADDY_LOG_FORMAT"," if you want the same format everywhere:",[253,1708,1709,1723],{},[256,1710,1711,1714,1715,1718,1719,1722],{},[458,1712,1713],{},"CADDY_LOG_FORMAT=console"," if you read logs by eye with ",[458,1716,1717],{},"docker compose logs"," or ",[458,1720,1721],{},"docker service logs"," and want the colored, human-readable lines whether or not a terminal is attached.",[256,1724,1725,1728],{},[458,1726,1727],{},"CADDY_LOG_FORMAT=json"," if a container runs with a terminal attached but you still want structured logs.",[238,1730,1731,1732,1735,1736,1741],{},"In both formats the request log redacts the ",[458,1733,1734],{},"authorization"," query parameter, so the JWT that Mercure 0.x subscribers pass in the URL never lands in your logs. This is the same filter that ",[431,1737,1740],{"href":1738,"rel":1739,"target":452},"https://github.com/php/frankenphp/blob/main/caddy/frankenphp/Caddyfile",[1618],"FrankenPHP's own Caddyfile"," recommends.",[450,1743,1744],{},[238,1745,1746,1747,1749,1750,1698,1753,1755,1756,438],{},"Laravel Octane only relays FrankenPHP's ",[458,1748,1639],{}," and only understands JSON, so leave ",[458,1751,1752],{},"CADDY_LOG_OUTPUT",[458,1754,1705],{}," at their defaults when you run Octane. See ",[431,1757,1759],{"href":1758},"/docs/framework-guides/laravel/octane#logging","Logging with Octane",[238,1761,1762,1763,1765,1766,1769,1770,1773],{},"Control the verbosity with ",[458,1764,790],{},". It defaults to ",[458,1767,1768],{},"info"," for FrankenPHP so request logs are included. Set it to ",[458,1771,1772],{},"warn"," to log problems only.",[245,1775,1777],{"id":1776},"mercure","Mercure",[238,1779,1780,1784,1785,1788],{},[431,1781,1777],{"href":1782,"rel":1783,"target":452},"https://mercure.rocks",[1618]," pushes real-time updates from your app to the browser. FrankenPHP has a Mercure hub built in, and you turn it on with environment variables instead of editing a Caddyfile. The hub answers at ",[458,1786,1787],{},"/.well-known/mercure"," on the same ports as your app, in classic mode and with Laravel Octane.",[585,1790,1792],{"className":587,"code":1791,"filename":589,"language":590,"meta":10,"style":10},"services:\n  php:\n    image: serversideup/php:8.5-frankenphp\n    ports:\n      - \"80:8080\"\n    volumes:\n      - ./:/var/www/html\n    environment:\n      MERCURE_ENABLED: \"true\"\n      MERCURE_TRUSTED_ISSUERS: \"https://example.com\"\n      MERCURE_PUBLISHER_JWT_KEY: \"${MERCURE_JWT_SECRET}\"\n      MERCURE_SUBSCRIBER_JWT_KEY: \"${MERCURE_JWT_SECRET}\"\n",[458,1793,1794,1800,1806,1814,1820,1826,1832,1838,1844,1854,1864,1874],{"__ignoreMap":10},[594,1795,1796,1798],{"class":596,"line":597},[594,1797,601],{"class":600},[594,1799,605],{"class":604},[594,1801,1802,1804],{"class":596,"line":608},[594,1803,611],{"class":600},[594,1805,605],{"class":604},[594,1807,1808,1810,1812],{"class":596,"line":616},[594,1809,619],{"class":600},[594,1811,622],{"class":604},[594,1813,626],{"class":625},[594,1815,1816,1818],{"class":596,"line":629},[594,1817,1209],{"class":600},[594,1819,605],{"class":604},[594,1821,1822,1824],{"class":596,"line":637},[594,1823,1217],{"class":604},[594,1825,1415],{"class":625},[594,1827,1828,1830],{"class":596,"line":644},[594,1829,1240],{"class":600},[594,1831,605],{"class":604},[594,1833,1834,1836],{"class":596,"line":1214},[594,1835,1217],{"class":604},[594,1837,1250],{"class":625},[594,1839,1840,1842],{"class":596,"line":1223},[594,1841,632],{"class":600},[594,1843,605],{"class":604},[594,1845,1846,1849,1851],{"class":596,"line":1231},[594,1847,1848],{"class":600},"      MERCURE_ENABLED",[594,1850,622],{"class":604},[594,1852,1853],{"class":625},"\"true\"\n",[594,1855,1856,1859,1861],{"class":596,"line":1237},[594,1857,1858],{"class":600},"      MERCURE_TRUSTED_ISSUERS",[594,1860,622],{"class":604},[594,1862,1863],{"class":625},"\"https://example.com\"\n",[594,1865,1866,1869,1871],{"class":596,"line":1245},[594,1867,1868],{"class":600},"      MERCURE_PUBLISHER_JWT_KEY",[594,1870,622],{"class":604},[594,1872,1873],{"class":625},"\"${MERCURE_JWT_SECRET}\"\n",[594,1875,1876,1879,1881],{"class":596,"line":1253},[594,1877,1878],{"class":600},"      MERCURE_SUBSCRIBER_JWT_KEY",[594,1880,622],{"class":604},[594,1882,1873],{"class":625},[238,1884,1885,1886,1889,1890,1893,1894,438],{},"Docker Compose reads ",[458,1887,1888],{},"MERCURE_JWT_SECRET"," from your ",[458,1891,1892],{},".env"," file. Generate a secret with ",[458,1895,1896],{},"openssl rand -base64 32",[307,1898,1899,1912],{},[310,1900,1901],{},[313,1902,1903,1906,1909],{},[316,1904,1905],{},"Variable",[316,1907,1908],{},"Default",[316,1910,1911],{},"Description",[326,1913,1914,1932,1951,1963,1981,1993,2007],{},[313,1915,1916,1921,1925],{},[331,1917,1918],{},[458,1919,1920],{},"MERCURE_ENABLED",[331,1922,1923],{},[458,1924,743],{},[331,1926,1927,1928,1931],{},"Set to ",[458,1929,1930],{},"true"," to turn on the Mercure hub",[313,1933,1934,1939,1944],{},[331,1935,1936],{},[458,1937,1938],{},"MERCURE_TRUSTED_ISSUERS",[331,1940,1941],{},[458,1942,1943],{},"https://localhost",[331,1945,1946,1947,1950],{},"The ",[458,1948,1949],{},"iss"," claim your tokens carry, usually your app's URL. The hub rejects tokens from any other issuer",[313,1952,1953,1958,1960],{},[331,1954,1955],{},[458,1956,1957],{},"MERCURE_PUBLISHER_JWT_KEY",[331,1959],{},[331,1961,1962],{},"Shared secret or PEM public key that verifies publisher tokens. Required when the hub is on",[313,1964,1965,1970,1975],{},[331,1966,1967],{},[458,1968,1969],{},"MERCURE_PUBLISHER_JWT_ALG",[331,1971,1972],{},[458,1973,1974],{},"HS256",[331,1976,1977,1978],{},"Algorithm for the publisher key. A PEM key needs an asymmetric algorithm such as ",[458,1979,1980],{},"RS256",[313,1982,1983,1988,1990],{},[331,1984,1985],{},[458,1986,1987],{},"MERCURE_SUBSCRIBER_JWT_KEY",[331,1989],{},[331,1991,1992],{},"Shared secret or PEM public key that verifies subscriber tokens. Required when the hub is on",[313,1994,1995,2000,2004],{},[331,1996,1997],{},[458,1998,1999],{},"MERCURE_SUBSCRIBER_JWT_ALG",[331,2001,2002],{},[458,2003,1974],{},[331,2005,2006],{},"Algorithm for the subscriber key",[313,2008,2009,2014,2019],{},[331,2010,2011],{},[458,2012,2013],{},"MERCURE_EXTRA_DIRECTIVES",[331,2015,2016],{},[458,2017,2018],{},"\"\"",[331,2020,2021,2022,2027],{},"More ",[431,2023,2026],{"href":2024,"rel":2025,"target":452},"https://mercure.rocks/docs/deployment/configuration",[1618],"Mercure directives",", one per line",[238,2029,2030,2031,2033],{},"The hub only accepts subscribers with a valid token. Use ",[458,2032,2013],{}," to allow anonymous subscribers to public updates or to set CORS origins:",[585,2035,2037],{"className":587,"code":2036,"filename":589,"language":590,"meta":10,"style":10},"    environment:\n      MERCURE_EXTRA_DIRECTIVES: |\n        anonymous\n        cors_origins https://example.com\n",[458,2038,2039,2045,2055,2060],{"__ignoreMap":10},[594,2040,2041,2043],{"class":596,"line":597},[594,2042,632],{"class":600},[594,2044,605],{"class":604},[594,2046,2047,2050,2052],{"class":596,"line":608},[594,2048,2049],{"class":600},"      MERCURE_EXTRA_DIRECTIVES",[594,2051,622],{"class":604},[594,2053,2054],{"class":1287},"|\n",[594,2056,2057],{"class":596,"line":616},[594,2058,2059],{"class":625},"        anonymous\n",[594,2061,2062],{"class":596,"line":629},[594,2063,2064],{"class":625},"        cors_origins https://example.com\n",[747,2066,2067],{},[238,2068,2069,2070,2075,2076,778,2078,2081,2082,2085,2086,2089],{},"FrankenPHP 1.13 includes Mercure 1.0, which expects ",[431,2071,2074],{"href":2072,"rel":2073,"target":452},"https://github.com/dunglas/mercure/blob/v1.0.3/docs/UPGRADE.md#migrate-your-tokens",[1618],"OAuth 2.0 access tokens"," with ",[458,2077,1949],{},[458,2079,2080],{},"aud",", and ",[458,2083,2084],{},"exp"," claims. If your app or library still signs Mercure 0.x tokens, set ",[458,2087,2088],{},"MERCURE_EXTRA_DIRECTIVES: \"protocol_version_compatibility 8\""," while you migrate. Compatibility mode relaxes token checks, so remove it once your tokens are updated.",[245,2091,2093],{"id":2092},"environment-variables","Environment Variables",[238,2095,2096],{},"The FrankenPHP variation supports extensive customization through environment variables.",[498,2098,2100],{"id":2099},"frankenphpcaddy-configuration","FrankenPHP/Caddy Configuration",[307,2102,2103,2113],{},[310,2104,2105],{},[313,2106,2107,2109,2111],{},[316,2108,1905],{},[316,2110,1908],{},[316,2112,1911],{},[326,2114,2115,2129,2143,2163,2189,2203,2217,2231,2259,2272,2286,2300,2319,2334,2349,2362],{},[313,2116,2117,2122,2126],{},[331,2118,2119],{},[458,2120,2121],{},"FRANKENPHP_CONFIG",[331,2123,2124],{},[458,2125,2018],{},[331,2127,2128],{},"FrankenPHP-specific configuration (e.g., worker mode)",[313,2130,2131,2136,2140],{},[331,2132,2133],{},[458,2134,2135],{},"CADDY_SERVER_ROOT",[331,2137,2138],{},[458,2139,1150],{},[331,2141,2142],{},"Document root for the application",[313,2144,2145,2150,2154],{},[331,2146,2147],{},[458,2148,2149],{},"CADDY_AUTO_HTTPS",[331,2151,2152],{},[458,2153,777],{},[331,2155,2156,2157,2160,2161,785],{},"Enable automatic HTTPS (",[458,2158,2159],{},"on","/",[458,2162,777],{},[313,2164,2165,2170,2174],{},[331,2166,2167],{},[458,2168,2169],{},"CADDY_ACME_PROFILE",[331,2171,2172],{},[458,2173,777],{},[331,2175,2176,2177,778,2179,778,2182,2185,2186],{},"Let's Encrypt certificate profile: ",[458,2178,777],{},[458,2180,2181],{},"shortlived",[458,2183,2184],{},"tlsserver",", or ",[458,2187,2188],{},"classic",[313,2190,2191,2196,2200],{},[331,2192,2193],{},[458,2194,2195],{},"CADDY_HTTP_PORT",[331,2197,2198],{},[458,2199,525],{},[331,2201,2202],{},"HTTP port",[313,2204,2205,2210,2214],{},[331,2206,2207],{},[458,2208,2209],{},"CADDY_HTTPS_PORT",[331,2211,2212],{},[458,2213,532],{},[331,2215,2216],{},"HTTPS port",[313,2218,2219,2224,2228],{},[331,2220,2221],{},[458,2222,2223],{},"CADDY_ADMIN",[331,2225,2226],{},[458,2227,777],{},[331,2229,2230],{},"Caddy admin API endpoint",[313,2232,2233,2237,2242],{},[331,2234,2235],{},[458,2236,1705],{},[331,2238,2239],{},[458,2240,2241],{},"auto",[331,2243,2244,2245,2247,2248,2250,2251,2254,2255,2185,2257],{},"Log format: ",[458,2246,2241],{}," (Caddy's default, ",[458,2249,1674],{}," on a terminal and ",[458,2252,2253],{},"json"," otherwise), ",[458,2256,1674],{},[458,2258,2253],{},[313,2260,2261,2265,2269],{},[331,2262,2263],{},[458,2264,1752],{},[331,2266,2267],{},[458,2268,1639],{},[331,2270,2271],{},"Log output destination",[313,2273,2274,2279,2283],{},[331,2275,2276],{},[458,2277,2278],{},"CADDY_GLOBAL_OPTIONS",[331,2280,2281],{},[458,2282,2018],{},[331,2284,2285],{},"Additional Caddy global options",[313,2287,2288,2293,2297],{},[331,2289,2290],{},[458,2291,2292],{},"CADDY_SERVER_EXTRA_DIRECTIVES",[331,2294,2295],{},[458,2296,2018],{},[331,2298,2299],{},"Additional Caddy server directives",[313,2301,2302,2306,2310],{},[331,2303,2304],{},[458,2305,773],{},[331,2307,2308],{},[458,2309,777],{},[331,2311,2312,2313,778,2315,2185,2317],{},"SSL mode: ",[458,2314,777],{},[458,2316,781],{},[458,2318,784],{},[313,2320,2321,2326,2331],{},[331,2322,2323],{},[458,2324,2325],{},"SSL_CERTIFICATE_FILE",[331,2327,2328],{},[458,2329,2330],{},"/etc/ssl/private/self-signed-web.crt",[331,2332,2333],{},"Path to SSL certificate",[313,2335,2336,2341,2346],{},[331,2337,2338],{},[458,2339,2340],{},"SSL_PRIVATE_KEY_FILE",[331,2342,2343],{},[458,2344,2345],{},"/etc/ssl/private/self-signed-web.key",[331,2347,2348],{},"Path to SSL private key",[313,2350,2351,2355,2359],{},[331,2352,2353],{},[458,2354,572],{},[331,2356,2357],{},[458,2358,565],{},[331,2360,2361],{},"Path for health check endpoint",[313,2363,2364,2369,2373],{},[331,2365,2366],{},[458,2367,2368],{},"SERVER_NAME",[331,2370,2371],{},[458,2372,2018],{},[331,2374,2375],{},"Domain name for automatic HTTPS",[440,2377,2378],{"to":223},[238,2379,2380,2381,438],{},"For a complete list of available environment variables, see the ",[431,2382,2383],{"href":223},"Environment Variable Specification →",[498,2385,2387],{"id":2386},"php-configuration","PHP Configuration",[307,2389,2390,2400],{},[310,2391,2392],{},[313,2393,2394,2396,2398],{},[316,2395,1905],{},[316,2397,1908],{},[316,2399,1911],{},[326,2401,2402,2417,2432,2447,2462,2477,2491,2511,2526],{},[313,2403,2404,2409,2414],{},[331,2405,2406],{},[458,2407,2408],{},"PHP_MEMORY_LIMIT",[331,2410,2411],{},[458,2412,2413],{},"256M",[331,2415,2416],{},"Maximum memory a script can use",[313,2418,2419,2424,2429],{},[331,2420,2421],{},[458,2422,2423],{},"PHP_MAX_EXECUTION_TIME",[331,2425,2426],{},[458,2427,2428],{},"99",[331,2430,2431],{},"Maximum time a script can run (seconds)",[313,2433,2434,2439,2444],{},[331,2435,2436],{},[458,2437,2438],{},"PHP_UPLOAD_MAX_FILE_SIZE",[331,2440,2441],{},[458,2442,2443],{},"100M",[331,2445,2446],{},"Maximum upload file size",[313,2448,2449,2454,2459],{},[331,2450,2451],{},[458,2452,2453],{},"PHP_FILE_UPLOADS",[331,2455,2456],{},[458,2457,2458],{},"On",[331,2460,2461],{},"Whether HTTP file uploads are allowed",[313,2463,2464,2469,2474],{},[331,2465,2466],{},[458,2467,2468],{},"PHP_MAX_FILE_UPLOADS",[331,2470,2471],{},[458,2472,2473],{},"20",[331,2475,2476],{},"Maximum number of files per request",[313,2478,2479,2484,2488],{},[331,2480,2481],{},[458,2482,2483],{},"PHP_POST_MAX_SIZE",[331,2485,2486],{},[458,2487,2443],{},[331,2489,2490],{},"Maximum POST request size",[313,2492,2493,2498,2503],{},[331,2494,2495],{},[458,2496,2497],{},"PHP_OPCACHE_ENABLE",[331,2499,2500],{},[458,2501,2502],{},"0",[331,2504,2505,2506,2160,2508,785],{},"Enable OPcache (",[458,2507,2502],{},[458,2509,2510],{},"1",[313,2512,2513,2518,2523],{},[331,2514,2515],{},[458,2516,2517],{},"PHP_OPCACHE_REVALIDATE_FREQ",[331,2519,2520],{},[458,2521,2522],{},"2",[331,2524,2525],{},"How often to check for file changes (seconds), only when timestamps are validated",[313,2527,2528,2533,2537],{},[331,2529,2530],{},[458,2531,2532],{},"PHP_OPCACHE_VALIDATE_TIMESTAMPS",[331,2534,2535],{},[458,2536,2502],{},[331,2538,2539,2540,2160,2542,2544,2545,2547],{},"Whether to check files for changes (",[458,2541,2502],{},[458,2543,2510],{},"). Set to ",[458,2546,2510],{}," when mounting code as a volume with OPcache enabled",[245,2549,2551],{"id":2550},"caddy-configuration","Caddy Configuration",[238,2553,2554],{},"FrankenPHP uses Caddy's configuration format (Caddyfile) instead of NGINX configuration.",[498,2556,2558],{"id":2557},"adding-your-own-caddyfile-rules","Adding your own Caddyfile rules",[238,2560,2561,2562,2566,2567,778,2569,2571],{},"Most changes only need one of the ",[431,2563,2565],{"href":2564},"#frankenphpcaddy-configuration","environment variables"," above, such as ",[458,2568,2135],{},[458,2570,773],{},", or the port settings. When you need a rule the variables don't cover, add raw Caddyfile config at the level where it belongs:",[307,2573,2574,2590],{},[310,2575,2576],{},[313,2577,2578,2581,2584,2587],{},[316,2579,2580],{},"Level",[316,2582,2583],{},"What goes here",[316,2585,2586],{},"Environment variable",[316,2588,2589],{},"Folder",[326,2591,2592,2618,2647],{},[313,2593,2594,2597,2609,2613],{},[331,2595,2596],{},"Global",[331,2598,2599,2604,2605,2608],{},[431,2600,2603],{"href":2601,"rel":2602,"target":452},"https://caddyserver.com/docs/caddyfile/options",[1618],"Global options",", including Caddy's ",[458,2606,2607],{},"servers"," option",[331,2610,2611],{},[458,2612,2278],{},[331,2614,2615],{},[458,2616,2617],{},"/etc/frankenphp/caddyfile-global.d/",[313,2619,2620,2623,2638,2642],{},[331,2621,2622],{},"Server",[331,2624,2625,2630,2631,778,2634,2637],{},[431,2626,2629],{"href":2627,"rel":2628,"target":452},"https://caddyserver.com/docs/caddyfile/directives",[1618],"Directives"," for your app, like ",[458,2632,2633],{},"header",[458,2635,2636],{},"redir",", and request matchers",[331,2639,2640],{},[458,2641,2292],{},[331,2643,2644],{},[458,2645,2646],{},"/etc/frankenphp/caddyfile-server.d/",[313,2648,2649,2652,2655,2658],{},[331,2650,2651],{},"New sites",[331,2653,2654],{},"Extra site blocks, like a second domain or a reverse proxy",[331,2656,2657],{},"None",[331,2659,2660],{},[458,2661,2662],{},"/etc/frankenphp/caddyfile.d/",[238,2664,2665,2666,2669,2670,2673,2674,1698,2676,2678],{},"Every ",[458,2667,2668],{},".caddyfile"," file in a folder is imported at that level. Use the environment variables for a quick one-liner and the folders for anything longer. The folders also work with ",[431,2671,394],{"href":2672},"/docs/framework-guides/laravel/octane#octane-options",", which replaces ",[458,2675,2278],{},[458,2677,2292],{}," with its own values.",[238,2680,2681],{},"Two more variables cover FrankenPHP itself:",[307,2683,2684,2695],{},[310,2685,2686],{},[313,2687,2688,2690,2692],{},[316,2689,1905],{},[316,2691,2583],{},[316,2693,2694],{},"Official Documentation",[326,2696,2697,2720],{},[313,2698,2699,2703,2713],{},[331,2700,2701],{},[458,2702,2121],{},[331,2704,2705,2706,2709,2710],{},"Options inside the global ",[458,2707,2708],{},"frankenphp"," block, like ",[458,2711,2712],{},"num_threads",[331,2714,2715],{},[431,2716,2719],{"href":2717,"rel":2718,"target":452},"https://frankenphp.dev/docs/config/#caddyfile-config",[1618],"FrankenPHP Configuration",[313,2721,2722,2727,2734],{},[331,2723,2724],{},[458,2725,2726],{},"CADDY_PHP_SERVER_OPTIONS",[331,2728,2729,2730,2733],{},"Options inside your app's ",[458,2731,2732],{},"php_server"," block",[331,2735,2736],{},[431,2737,2739],{"href":2717,"rel":2738,"target":452},[1618],"FrankenPHP PHP Server Options",[238,2741,2742,2743,2746],{},"This is where each one lands in ",[458,2744,2745],{},"/etc/frankenphp/Caddyfile",":",[585,2748,2752],{"className":2749,"code":2750,"filename":2745,"language":2751,"meta":10,"style":10},"language-txt shiki shiki-themes github-dark","{\n    frankenphp {\n        FRANKENPHP_CONFIG\n    }\n    CADDY_GLOBAL_OPTIONS\n    caddyfile-global.d/*.caddyfile\n}\n\nyour app's site (one per listener that SSL_MODE creates) {\n    php_server {\n        CADDY_PHP_SERVER_OPTIONS\n    }\n    CADDY_SERVER_EXTRA_DIRECTIVES\n    caddyfile-server.d/*.caddyfile\n}\n\ncaddyfile.d/*.caddyfile\n","txt",[458,2753,2754,2759,2764,2769,2774,2779,2784,2789,2795,2800,2805,2810,2814,2819,2824,2829,2834],{"__ignoreMap":10},[594,2755,2756],{"class":596,"line":597},[594,2757,2758],{},"{\n",[594,2760,2761],{"class":596,"line":608},[594,2762,2763],{},"    frankenphp {\n",[594,2765,2766],{"class":596,"line":616},[594,2767,2768],{},"        FRANKENPHP_CONFIG\n",[594,2770,2771],{"class":596,"line":629},[594,2772,2773],{},"    }\n",[594,2775,2776],{"class":596,"line":637},[594,2777,2778],{},"    CADDY_GLOBAL_OPTIONS\n",[594,2780,2781],{"class":596,"line":644},[594,2782,2783],{},"    caddyfile-global.d/*.caddyfile\n",[594,2785,2786],{"class":596,"line":1214},[594,2787,2788],{},"}\n",[594,2790,2791],{"class":596,"line":1223},[594,2792,2794],{"emptyLinePlaceholder":2793},true,"\n",[594,2796,2797],{"class":596,"line":1231},[594,2798,2799],{},"your app's site (one per listener that SSL_MODE creates) {\n",[594,2801,2802],{"class":596,"line":1237},[594,2803,2804],{},"    php_server {\n",[594,2806,2807],{"class":596,"line":1245},[594,2808,2809],{},"        CADDY_PHP_SERVER_OPTIONS\n",[594,2811,2812],{"class":596,"line":1253},[594,2813,2773],{},[594,2815,2816],{"class":596,"line":1259},[594,2817,2818],{},"    CADDY_SERVER_EXTRA_DIRECTIVES\n",[594,2820,2821],{"class":596,"line":1266},[594,2822,2823],{},"    caddyfile-server.d/*.caddyfile\n",[594,2825,2827],{"class":596,"line":2826},15,[594,2828,2788],{},[594,2830,2832],{"class":596,"line":2831},16,[594,2833,2794],{"emptyLinePlaceholder":2793},[594,2835,2837],{"class":596,"line":2836},17,[594,2838,2839],{},"caddyfile.d/*.caddyfile\n",[275,2841,2843],{"id":2842},"add-rules-to-your-app","Add rules to your app",[238,2845,2846,2847,2850],{},"Put directives for your app in ",[458,2848,2849],{},"caddyfile-server.d/",". This example gives one JavaScript file a short cache, overriding the year-long cache the image sets for static assets:",[585,2852,2857],{"className":2853,"code":2854,"filename":2855,"language":2856,"meta":10,"style":10},"language-caddyfile shiki shiki-themes github-dark","@embed path /embed.js\nheader @embed >Cache-Control \"public, max-age=3600\"\n","embed-cache.caddyfile","caddyfile",[458,2858,2859,2864],{"__ignoreMap":10},[594,2860,2861],{"class":596,"line":597},[594,2862,2863],{},"@embed path /embed.js\n",[594,2865,2866],{"class":596,"line":608},[594,2867,2868],{},"header @embed >Cache-Control \"public, max-age=3600\"\n",[238,2870,2871],{},"Mount the file in development, or copy it into your image for production:",[2873,2874,2875,2913],"code-group",{},[585,2876,2878],{"className":587,"code":2877,"filename":589,"language":590,"meta":10,"style":10},"services:\n  php:\n    image: serversideup/php:8.5-frankenphp\n    volumes:\n      - ./embed-cache.caddyfile:/etc/frankenphp/caddyfile-server.d/embed-cache.caddyfile\n",[458,2879,2880,2886,2892,2900,2906],{"__ignoreMap":10},[594,2881,2882,2884],{"class":596,"line":597},[594,2883,601],{"class":600},[594,2885,605],{"class":604},[594,2887,2888,2890],{"class":596,"line":608},[594,2889,611],{"class":600},[594,2891,605],{"class":604},[594,2893,2894,2896,2898],{"class":596,"line":616},[594,2895,619],{"class":600},[594,2897,622],{"class":604},[594,2899,626],{"class":625},[594,2901,2902,2904],{"class":596,"line":629},[594,2903,1240],{"class":600},[594,2905,605],{"class":604},[594,2907,2908,2910],{"class":596,"line":637},[594,2909,1217],{"class":604},[594,2911,2912],{"class":625},"./embed-cache.caddyfile:/etc/frankenphp/caddyfile-server.d/embed-cache.caddyfile\n",[585,2914,2919],{"className":2915,"code":2916,"filename":2917,"language":2918,"meta":10,"style":10},"language-dockerfile shiki shiki-themes github-dark","FROM serversideup/php:8.5-frankenphp\nCOPY embed-cache.caddyfile /etc/frankenphp/caddyfile-server.d/\n","Dockerfile","dockerfile",[458,2920,2921,2928],{"__ignoreMap":10},[594,2922,2923,2926],{"class":596,"line":597},[594,2924,2925],{"class":1287},"FROM",[594,2927,1140],{"class":604},[594,2929,2930,2933],{"class":596,"line":608},[594,2931,2932],{"class":1287},"COPY",[594,2934,2935],{"class":604}," embed-cache.caddyfile /etc/frankenphp/caddyfile-server.d/\n",[238,2937,2938,2939,2941,2942,2944,2945,2948,2949,2952],{},"Rules in ",[458,2940,2849],{}," apply on every listener ",[458,2943,773],{}," creates. With ",[458,2946,2947],{},"SSL_MODE=mixed",", that includes plain HTTP, so match on ",[458,2950,2951],{},"protocol https"," for anything that only belongs on HTTPS.",[450,2954,2955,2964,2989],{},[238,2956,2957,2958,1718,2961,2963],{},"Docker's health check goes through your app's site too. Leave the health check path out of any rule that matches every request, like ",[458,2959,2960],{},"basic_auth",[458,2962,2636],{},", or the container will be marked unhealthy:",[585,2965,2968],{"className":2853,"code":2966,"filename":2967,"language":2856,"meta":10,"style":10},"@protected not path /healthcheck {$HEALTHCHECK_PATH:/healthcheck}\nbasic_auth @protected {\n    admin $2a$14$KbVXTcgF3ZrK76FfvPLFj.kXOV/PH5pkAk.o53ct8bGdsl6yai9eC\n}\n","basic-auth.caddyfile",[458,2969,2970,2975,2980,2985],{"__ignoreMap":10},[594,2971,2972],{"class":596,"line":597},[594,2973,2974],{},"@protected not path /healthcheck {$HEALTHCHECK_PATH:/healthcheck}\n",[594,2976,2977],{"class":596,"line":608},[594,2978,2979],{},"basic_auth @protected {\n",[594,2981,2982],{"class":596,"line":616},[594,2983,2984],{},"    admin $2a$14$KbVXTcgF3ZrK76FfvPLFj.kXOV/PH5pkAk.o53ct8bGdsl6yai9eC\n",[594,2986,2987],{"class":596,"line":629},[594,2988,2788],{},[238,2990,2991,2992,438],{},"Generate the password hash with ",[458,2993,2994],{},"docker run --rm -it serversideup/php:8.5-frankenphp frankenphp hash-password",[275,2996,2998],{"id":2997},"add-another-site","Add another site",[238,3000,3001,3002,3005],{},"Files in ",[458,3003,3004],{},"caddyfile.d/"," sit at the top level of the Caddyfile, outside your app's site. Use them for a whole new site block:",[585,3007,3010],{"className":2853,"code":3008,"filename":3009,"language":2856,"meta":10,"style":10},"http://docs.example.com:{$CADDY_HTTP_PORT:8080} {\n    reverse_proxy docs:3000\n}\n","docs-proxy.caddyfile",[458,3011,3012,3017,3022],{"__ignoreMap":10},[594,3013,3014],{"class":596,"line":597},[594,3015,3016],{},"http://docs.example.com:{$CADDY_HTTP_PORT:8080} {\n",[594,3018,3019],{"class":596,"line":608},[594,3020,3021],{},"    reverse_proxy docs:3000\n",[594,3023,3024],{"class":596,"line":616},[594,3025,2788],{},[238,3027,3028,3029,3031,3032,3034],{},"Rules for your app don't work here. The ",[458,3030,2855],{}," example above fails in this folder with \"request matchers may not be defined globally\", so put rules like that in ",[458,3033,2849],{}," instead.",[275,3036,3038],{"id":3037},"replace-the-whole-caddyfile","Replace the whole Caddyfile",[238,3040,3041,3042,3044],{},"If you need a completely different setup, copy your own file over ",[458,3043,2745],{},". You then own everything the image's Caddyfile does, including SSL modes, security headers, and the health check endpoint, so reach for the folders first.",[245,3046,3048],{"id":3047},"further-customization","Further Customization",[238,3050,3051],{},"If you need to customize the container further, reference the docs below:",[253,3053,3054,3059,3064,3072],{},[256,3055,3056,3058],{},[431,3057,222],{"href":223}," - See which environment variables are available to customize PHP and Caddy settings.",[256,3060,3061,3063],{},[431,3062,226],{"href":227}," - See which commands are available to run inside the container.",[256,3065,3066,3071],{},[431,3067,3070],{"href":3068,"rel":3069,"target":452},"https://frankenphp.dev/",[1618],"FrankenPHP Documentation"," - Official FrankenPHP documentation for advanced features.",[256,3073,3074,3079],{},[431,3075,3078],{"href":3076,"rel":3077,"target":452},"https://caddyserver.com/docs/",[1618],"Caddy Documentation"," - Official Caddy documentation for web server configuration.",[3081,3082,3083],"style",{},"html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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 pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}",{"title":10,"searchDepth":608,"depth":608,"links":3085},[3086,3087,3088,3096,3097,3098,3104,3108,3109,3110,3114,3117],{"id":247,"depth":608,"text":248},{"id":304,"depth":608,"text":305},{"id":492,"depth":608,"text":493,"children":3089},[3090,3091,3092,3093,3094,3095],{"id":500,"depth":616,"text":501},{"id":548,"depth":616,"text":549},{"id":664,"depth":616,"text":665},{"id":714,"depth":616,"text":715},{"id":757,"depth":616,"text":758},{"id":811,"depth":616,"text":812},{"id":1000,"depth":608,"text":1001},{"id":1053,"depth":608,"text":1054},{"id":1091,"depth":608,"text":1092,"children":3099},[3100,3101,3102,3103],{"id":1098,"depth":616,"text":1099},{"id":1153,"depth":616,"text":1154},{"id":1317,"depth":616,"text":394},{"id":1335,"depth":616,"text":1336},{"id":1362,"depth":608,"text":372,"children":3105},[3106,3107],{"id":1376,"depth":616,"text":1377},{"id":1500,"depth":616,"text":1501},{"id":1609,"depth":608,"text":1610},{"id":1776,"depth":608,"text":1777},{"id":2092,"depth":608,"text":2093,"children":3111},[3112,3113],{"id":2099,"depth":616,"text":2100},{"id":2386,"depth":616,"text":2387},{"id":2550,"depth":608,"text":2551,"children":3115},[3116],{"id":2557,"depth":616,"text":2558},{"id":3047,"depth":608,"text":3048},"Learn how to use the FrankenPHP variation of the serversideup/php image.",null,{},{"title":78,"description":3118},"koXcKa8TDcaUpJ793SWP0zMPm990FPojSnmS3zzy0zU",[3124,3126],{"title":74,"path":75,"stem":76,"description":3125,"children":-1},"Learn how to use the FPM-NGINX variation of the serversideup/php image.",{"title":82,"path":83,"stem":84,"description":3127,"children":-1},"NGINX Unit has been archived. This guide helps you understand what happened and how to migrate to actively maintained alternatives.",1793279089499]