How to Deploy PHP to Docker Without Writing a Dockerfile

M
Miget Team
Writer
January 6, 2026
4 min read

You can containerize any PHP application without writing a Dockerfile using migetpacks. It uses FrankenPHP (a modern PHP application server built on Go and Caddy), auto-detects your PHP version and extensions from composer.json, and produces an optimized production image. One command, zero configuration.


Why Is Writing a Dockerfile for PHP So Complicated?

A production-ready PHP Dockerfile requires:

  • Choosing between Apache, nginx+PHP-FPM, or modern alternatives
  • Installing PHP extensions (pdo_pgsql, gd, intl, etc.)
  • Configuring opcache for production
  • Setting up Composer for dependency management
  • Detecting the web root (public/, web/, html/)
  • Production PHP settings (display_errors=Off, memory_limit, etc.)

Most tutorials use outdated Apache configurations or manual nginx setups. You end up with slow, bloated images.

How Do I Containerize a PHP App Without a Dockerfile?

Open your terminal, navigate to your PHP project, and run:

cd ~/projects/my-laravel-app

docker run --rm \
  -v "$PWD":/workspace/source \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e OUTPUT_IMAGE=my-laravel-app:latest \
  miget/migetpacks:latest

That's it. migetpacks will:

  1. Detect PHP from composer.json or index.php
  2. Read version from .php-version or composer.json
  3. Detect and install required extensions
  4. Run composer install with caching
  5. Detect the web root automatically
  6. Output a production-ready FrankenPHP image

What Is FrankenPHP?

FrankenPHP is a modern PHP application server built on Go and Caddy. It's:

  • Faster than nginx+PHP-FPM (no FastCGI overhead)
  • Simpler than Apache (single binary, no modules)
  • Modern with HTTP/2, HTTP/3, and automatic HTTPS
  • Production-ready with worker mode for long-running processes

How Does migetpacks Detect My PHP Version?

Version is resolved in this order:

SourceExample
.php-version8.3
composer.json (require.php)"php": ">=8.2"
Default8.3

Version constraints from composer.json (e.g., >=8.2, ^8.3) are normalized for Docker.

FrankenPHP supports PHP 8.2, 8.3, and 8.4. Older versions fall back to PHP 8.2 with a warning.

How Does PHP Extension Detection Work?

Extensions declared in composer.json under require with the ext- prefix are automatically installed:

{
  "require": {
    "ext-pdo_pgsql": "*",
    "ext-gd": "*",
    "ext-intl": "*"
  }
}

migetpacks reads your composer.json and installs all required extensions in the Docker image.

What Does the Generated Dockerfile Look Like?

# Build stage
FROM dunglas/frankenphp:builder-php8.3 AS builder
WORKDIR /build

# Install PHP extensions detected from composer.json
RUN apt-get update && apt-get install -y ... \
    && docker-php-ext-install pdo_pgsql gd ...

# Composer install with caching
COPY composer.json composer.lock* ./
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
    && composer install --no-dev --optimize-autoloader --no-scripts

COPY . .

# Runtime stage
FROM dunglas/frankenphp:php8.3
WORKDIR /app
COPY --from=builder --chown=1000:1000 /build /app

You never write or maintain this file - migetpacks handles it automatically.

How Does Web Root Detection Work?

migetpacks automatically detects the web root by checking for these directories (in order):

  1. web/
  2. public/
  3. html/
  4. www/
  5. . (project root, fallback)

Laravel apps use public/, Symfony uses public/, and WordPress often uses the root.

What PHP Settings Are Applied for Production?

SettingDefault
memory_limit256M
max_execution_time30
upload_max_filesize32M
opcache.enable1
display_errorsOff
session.cookie_secure1

Override at runtime with PHP_INI_* environment variables:

docker run -e PHP_INI_MEMORY_LIMIT=512M my-laravel-app:latest

How Do I Build a Laravel App?

Laravel works out of the box:

cd ~/projects/my-laravel-app

docker run --rm \
  -v "$PWD":/workspace/source \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e OUTPUT_IMAGE=my-laravel:latest \
  miget/migetpacks:latest

Run the container:

docker run -p 8000:8000 \
  -e APP_KEY=base64:your-app-key \
  my-laravel:latest

Next Steps

Stay UpdatedWith Latest Posts

Subscribe to our newsletter and never miss a new blog post, update, or special offer from the Miget team.