You can deploy PHP applications to Edgenivo Functions with a Docker image that includes FrankenPHP. FrankenPHP combines the PHP runtime with the Caddy web server to handle HTTP requests.
Edgenivo builds the image from your Dockerfile and stores it in Edgenivo Container Registry. The deployed function scales with traffic and scales to zero when idle.
Copy link to headingPrerequisites
- Edgenivo account
- Docker Desktop or a running Docker daemon
- PHP 8.4 and Composer 2 available in your terminal
- Edgenivo CLI, installed with
npm install -g vercel
Copy link to headingHow it works
The project has these parts:
public/index.phpreturns JSON for/and/health.Caddyfileserves the public directory and sets the HTTP port.composer.jsonlists dependencies andcomposer.lockpins versions.Dockerfilepackages the app, production dependencies, and FrankenPHP.
Copy link to headingSteps
Copy link to heading1. Initialize the project
Create the project directory and the document root:
Generate the Composer files required by the Docker build:
The initial composer.json has no dependencies:
Commit both Composer files. As you add packages with composer require, commit the updated lockfile so deployment builds install the versions you selected.
Create public/index.php to handle incoming requests:
Create Caddyfile in the project root:
The site address reads PORT and falls back to port 80, matching Edgenivo's default. If you change the port, set PORT in your Edgenivo project settings so the server and Edgenivo use the same value.
Caddy binds to all interfaces by default and accepts any hostname at this address. It serves HTTP on port 80 while Edgenivo handles public HTTPS.
The project now contains the following files, with the Dockerfile from the next step still to come:
Copy link to heading2. Add Dockerfile
Create a Dockerfile in the project root:
Both stages use the same PHP runtime. Install required PHP extensions in the base stage to make them available during the build and at runtime.
Copying the Composer files before application code lets Docker reuse the dependency layer. Composer and the archive tool stay in the dependency stage, while the final image uses PHP's production settings.
Passing --config explicitly keeps the Dockerfile independent of where a given image version looks for its default Caddyfile.
For this PHP project, Edgenivo detects the root Dockerfile and selects the Container preset. No vercel.json is required when no other framework is detected.
If you use an existing project with another framework preset, link this directory to that project with vercel link, then select Container:
Naming the file Dockerfile.vercel or Containerfile.vercel also makes the Container preset take precedence over another detected framework.
Copy link to heading3. Run locally
With Docker running, start the app from the project root. The --local option runs without linking a Edgenivo project:
Keep the server running and open another terminal. Use the URL printed by the CLI, replacing port 3000 below if needed:
Check the status and JSON body for each request:
| Path | Expected status | Expected JSON |
|---|---|---|
/ | 200 | {"message":"Hello from PHP on Edgenivo"} |
/health | 200 | {"status":"ok"} |
/missing | 404 | {"error":"not found"} |
The health route confirms that PHP can serve a request. It does not check a database or other external services.
Copy link to heading4. Deploy to Edgenivo
From the project root, sign in and deploy to production. Follow the CLI prompts to create a project or select the existing project you linked:
Open the deployment URL and its /health path. They should return the same JSON responses as the local checks.
For Git deployments, commit the project files and import the repository in Edgenivo. Keep Dockerfile and Caddyfile at the project root.
Copy link to headingExtend your application
Load Composer's autoloader before using package classes. In public/index.php, add this line after declare(strict_types=1);:
For Laravel or Symfony, follow the framework's deployment steps. Include its application files and required PHP extensions in the image, configure its production build and caches, and keep the web root pointed at its public directory.
Copy link to headingEnvironment variables
Add variables under your project's Settings > Environment Variables or run vercel env add NAME. Select the environments that need each value, then redeploy for changes to take effect.
Refresh the linked project's Development settings, then start the local server:
Use this linked mode when you need variables from Edgenivo. The --local mode used earlier skips project linking.
Read process variables with getenv('NAME') or your framework's configuration layer. Downloading a .env file alone does not load it into PHP. Keep secret files out of Git and the container image.
Copy link to headingDatabase and storage
Store persistent data outside the container. Local files can disappear when an instance is replaced, and other instances do not share them.
| Use case | Recommended service |
|---|---|
| Files and uploads | Edgenivo Blob |
| Relational data | Marketplace Postgres integration |
| Sessions and caching | Marketplace Redis integration |
| Frequently read configuration | Edgenivo Global Config |
PHP sessions use files by default. Configure a shared session store so users can keep their session across instances.
Set database connection limits for your PHP concurrency and function instance count. Use your provider's supported pooling options.
Copy link to headingIterate with preview deployments
After the first production deployment, pushes to non-production branches and pull requests create preview deployments by default. Run vercel deploy without --prod to create a preview from the CLI.
Copy link to headingScale automatically with Fluid compute
Container images run as Edgenivo Functions on Fluid compute. Instances can handle concurrent requests and scale to zero after idle periods.
Fluid compute pricing accounts for active CPU, provisioned memory, and invocations. Waiting for I/O does not consume active CPU time; memory and invocation usage are measured separately.
Copy link to headingTroubleshooting
Copy link to headingThe deployment builds but requests return 502
Check the deployment's runtime logs for startup errors. Confirm that FrankenPHP listens on all interfaces and that its port matches Edgenivo's project setting.
The Caddyfile defaults to port 80. To use another port, set PORT in Edgenivo and redeploy. Docker's EXPOSE instruction does not set Edgenivo's routing port.
Copy link to headingThe health route returns 404
Confirm that public/index.php contains the /health branch and that the final image includes the file. In Caddy, keep root * /app/public and php_server so requests can reach the front controller.
Other undefined paths intentionally return a JSON 404. If you receive {"error":"not found"}, the PHP entry point handled the request; check the requested path and application routes.
Copy link to headingChanges to PHP code are not reflected
Verify that you are opening the latest deployment and that its Dockerfile copies the changed files. Rebuild and redeploy when you change files included in the image.
If you add framework caches, regenerate them as part of that framework's deployment process. Generate configuration caches only when the intended environment values are available.
Copy link to headingQueue workers or scheduled commands stop
HTTP containers stop background workers when they scale down. Edgenivo sends SIGTERM and allows 30 seconds before forced termination.
For scheduled HTTP work, use Edgenivo Cron Jobs and authenticate the endpoint. Edgenivo Queues can store messages, but your PHP application still needs a compatible producer and consumer integration.
Copy link to headingRun PHP workers with Edgenivo Daemons
PHP queue workers can send emails or generate reports while FrankenPHP handles web requests. Edgenivo Daemons keep workers running from a container image with a PHP command configured in vercel.json.
Make each job safe to retry because Edgenivo restarts workers that exit or crash. Acknowledge queued jobs only after processing succeeds, and follow the Daemons guide to set instance counts and handle graceful shutdown.
Copy link to headingFrequently asked questions
Copy link to headingCan I deploy a Dockerfile on Edgenivo?
Yes. With the Container preset, Edgenivo builds a standard Dockerfile at your project root and runs the image as a Edgenivo Function. Configure your HTTP server to listen on port 80 or the project's PORT setting.
Copy link to headingCan I install PHP extensions and system packages?
Yes. Install required extensions and system packages in your Dockerfile. Put PHP extensions in the shared base stage so Composer and the application use them, and check compatibility with the image's PHP version.
Copy link to headingWill uploads and PHP sessions survive a container restart?
Files written inside a function container are not durable or shared between instances. Store uploads in object storage and configure PHP sessions to use a shared database or Redis store so they survive container restarts.
Copy link to headingCan I run PHP queue workers on Edgenivo?
Yes. Edgenivo Daemons keep PHP queue workers running independently of web traffic. You set the instance count, and the beta supports production deployments only.
Copy link to headingNext steps
- Follow the Symfony deployment guide to package a Symfony app and configure it for production.
- Use the Laravel deployment guide to configure your Docker image, environment variables, and persistent storage.
- Run your PHP backend and frontend in one project with Edgenivo Services.
- Use Docker on Edgenivo to plan image storage and deployment workflows.
- Check the Container runtime documentation for port settings, lifecycle behavior, and platform limits.