Files
2026-07-23 10:41:30 +03:00

15 KiB

FrankenPHP Docker Environment

A modern, lightweight Docker environment for PHP applications using FrankenPHP, featuring HTTP/2, HTTP/3, automatic HTTPS, and built-in Node.js support for multiple PHP frameworks.

Features

  • 🚀 FrankenPHP Server: Modern PHP server with HTTP/2, HTTP/3, and automatic HTTPS via Caddy
  • 🗄️ MariaDB Database: Persistent relational database for your applications
  • 📦 Node.js Integration: Full Node.js runtime (v20.x) for frontend tooling and build processes
  • 🎯 Multi-Framework Support: Optimized build targets for Laravel, Symfony, Magento2, WordPress, and OpenCart
  • 🧰 CLI Tools Included: Symfony CLI is available for Symfony projects and WP-CLI is included for WordPress workflows
  • 🗄️ Redis Support: A dedicated Redis container is included with health checks and PHP connectivity for supported stacks
  • 📝 PHP 8.0 - 8.5: Support for multiple PHP versions with configurable extensions
  • 🔧 Flexible Configuration: Local, proxy, and production modes
  • 🔒 Automatic HTTPS: Let's Encrypt SSL certificates in production
  • 🎨 Extension-Rich: Pre-installed essential PHP extensions (PDO/MySQL, Redis, APCu, and more)
  • ⚡ Alpine-Based: Lightweight, fast, and efficient container images
  • 🔄 Hot Reload: Automatic code reloading during development

Recently Added

  • Symfony CLI pre-installed for Symfony-based applications
  • WP-CLI pre-installed for WordPress administration and site management
  • Redis container support with health checks and framework-ready PHP integration

Requirements

  • Docker Desktop (or Docker Engine + Docker Compose)
  • 2GB+ RAM available
  • Terminal/Command-line access

Quick Start

1. Clone the Repository

git clone <repository-url>
cd franken

2. Configure Environment

cp .env.example .env

Edit the .env file with your preferred settings:

# Core Configuration
PHP_VERSION=8.4              # PHP version (8.0-8.5)
FRAMEWORK=opencart           # Framework: laravel, symfony, magento2, wordpress, opencart
MODE=proxy                   # Mode: local, prod, proxy
PORT=80                      # Local port
PROJECT_NAME=opencart        # Project name

# Database Configuration
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=database
MYSQL_USER_DATABASE=app
MYSQL_PASSWORD_DATABASE=secret

3. Start Services

docker-compose up -d

4. Access Your Application

Configuration Guide

Environment Variables

Variable Description Options
PHP_VERSION PHP version 8.0, 8.1, 8.2, 8.3, 8.4, 8.5
FRAMEWORK Target framework laravel, symfony, magento2, wordpress, opencart
MODE Run mode local (dev), proxy (behind reverse proxy), prod (production)
PORT HTTP port Any available port (default: 80)
PROJECT_NAME Project identifier Any alphanumeric name
MYSQL_ROOT_PASSWORD Database root password Your secure password
MYSQL_DATABASE Database name database
MYSQL_USER_DATABASE Database user app
MYSQL_PASSWORD_DATABASE Database user password Your secure password
SERVER_NAME Domain (prod mode) Your domain (e.g., example.com)

Framework-Specific Setup

Laravel

  1. Update .env:

    FRAMEWORK=laravel
    
  2. Uncomment Laravel volume in docker-compose.yml:

    volumes:
      - ./www:/app          # Instead of /app/public
    
  3. Start services:

    docker-compose up -d --build
    

Symfony

  1. Update .env:

    FRAMEWORK=symfony
    
  2. Uncomment Symfony volume in docker-compose.yml:

    volumes:
      - ./www:/app          # Instead of /app/public
    
  3. Build and start:

    docker-compose up -d --build
    

WordPress

  1. Update .env:

    FRAMEWORK=wordpress
    
  2. The default volume mount /app/public works for WordPress

  3. Start services:

    docker-compose up -d --build
    

OpenCart

  1. Update .env:

    FRAMEWORK=opencart
    
  2. Default configuration uses /app/public

  3. Start services:

    docker-compose up -d --build
    

Magento 2

  1. Update .env:

    FRAMEWORK=magento2
    
  2. Start services:

    docker-compose up -d --build
    

Modes Explained

  • local: Development mode with internal TLS disabled, suitable for local development
  • proxy: Designed for use behind a reverse proxy or load balancer
  • prod: Production mode with HTTPS enabled, automatic SSL certificates, and optimized PHP settings

Production Deployment

  1. Update .env:

    MODE=prod
    SERVER_NAME=yourdomain.com
    PHP_VERSION=8.4
    
  2. Enable HTTPS in docker-compose.yml:

    ports:
      - "443:443"           # HTTPS
      - "443:443/udp"       # HTTP/3
    
  3. Start services:

    docker-compose up -d --build
    
  4. FrankenPHP automatically obtains SSL certificates from Let's Encrypt

How to Run

Start Services

# Start in background
docker-compose up -d

# Start with output
docker-compose up

# Start and rebuild images
docker-compose up -d --build

Stop Services

docker-compose down

View Logs

# View all logs
docker-compose logs -f

# View specific service logs
docker-compose logs -f php
docker-compose logs -f db

Access Container Shell

# PHP container
docker-compose exec php sh

# Database container
docker-compose exec db mysql -u app -p

Development Workflow

Running Commands Inside Container

# Composer commands
docker-compose exec php composer install
docker-compose exec php composer require package/name

# NPM/Node commands
docker-compose exec php npm install
docker-compose exec php npm run dev
docker-compose exec php npm run build

# PHP CLI
docker-compose exec php php -v
docker-compose exec php php artisan migrate          # Laravel
docker-compose exec php bin/console doctrine:schema  # Symfony

# Database management
docker-compose exec db mysql -u app -p database

File Structure

franken/
├── docker-compose.yml    # Docker services configuration
├── Dockerfile           # Multi-stage PHP container build
├── .env                 # Environment configuration
├── php.ini             # Custom PHP settings
├── www/                # Web application root
│   └── index.php       # Entry point
└── README.md           # This file

PHP Configuration

Edit php.ini to customize PHP settings:

; Example configurations
display_errors = On
memory_limit = 512M
upload_max_filesize = 100M
post_max_size = 100M

Changes take effect after container restart:

docker-compose restart php

Redis Caching

Setup

Redis is included and pre-configured in docker-compose.yml. It runs in a separate container with:

  • Image: redis:alpine (lightweight, fast)
  • Persistent Storage: Redis data is stored in redis_data volume
  • Health Check: Built-in health check to verify Redis is running
  • Networking: Connected to app-network for internal PHP communication

Redis Service Configuration

Redis is automatically started with docker-compose up. To verify it's running:

# Check Redis container status
docker-compose ps redis

# Connect to Redis CLI
docker-compose exec redis redis-cli

# Test Redis connection from PHP container
docker-compose exec php php -r "
\$redis = new Redis();
\$redis->connect('redis', 6379);
echo 'Redis connected: ' . (\$redis->ping() ? 'OK' : 'FAILED');
\$redis->close();
"

Using Redis in Your Application

Laravel Example

Update your .env:

CACHE_DRIVER=redis
SESSION_DRIVER=redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=null

Install/configure in your Laravel app:

# Inside container
docker-compose exec php composer require predis/predis

# Or use PHP's native Redis extension (recommended)

PHP Native Example

<?php
$redis = new Redis();
$redis->connect('redis', 6379);

// Set a cache value
$redis->set('user:1:name', 'John Doe', 3600); // 1 hour TTL

// Get a value
$name = $redis->get('user:1:name');

// Check if key exists
if ($redis->exists('user:1:name')) {
    echo "Key exists";
}

// Delete a key
$redis->del('user:1:name');

// Increment counter
$redis->incr('page_views');

$redis->close();
?>

Symfony Example

Configure in config/packages/cache.yaml:

framework:
  cache:
    default_redis_provider: 'redis://redis:6379'
    pools:
      cache.app:
        adapter: cache.adapter.redis
        provider: 'redis://redis:6379'

WordPress Example

Use a Redis plugin like "Redis Object Cache" and configure:

define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', 6379);

Common Redis Operations

# Connect to Redis CLI
docker-compose exec redis redis-cli

# Inside redis-cli commands:
PING                                  # Check connection
SET mykey "Hello"                     # Set a key
GET mykey                             # Get a value
DEL mykey                             # Delete a key
KEYS *                                # List all keys
FLUSHDB                               # Clear all keys
INFO                                  # Show Redis info
MONITOR                               # Monitor commands in real-time

Redis Persistence

  • Data persists in the redis_data volume
  • If you need to reset Redis data: docker volume rm gold_redis_data
  • Configure persistence in docker-compose.yml if needed:
redis:
  command: redis-server --appendonly yes  # Enable AOF persistence

Troubleshooting Redis

# Check if Redis is running
docker-compose logs redis

# Restart Redis
docker-compose restart redis

# Clear Redis cache
docker-compose exec redis redis-cli FLUSHDB

# Monitor Redis activity
docker-compose exec redis redis-cli MONITOR

Docker Architecture

Multi-Stage Build

The Dockerfile uses multi-stage builds to optimize for different frameworks:

  • base: Foundation with core PHP extensions
  • node: Adds Node.js runtime
  • laravel: Laravel-specific extensions (Redis, APCu)
  • symfony: Symfony-specific extensions (APCu, Sodium)
  • wordpress: WordPress-specific configuration
  • opencart: OpenCart-specific configuration
  • magento2: Magento 2-specific configuration

Services

PHP Service (FrankenPHP)

  • Image: dunglas/frankenphp:php{PHP_VERSION}-alpine
  • Includes:
    • PHP 8.0-8.5
    • Node.js v20.x
    • Caddy web server
    • Framework-specific extensions

Database Service (MariaDB)

  • Image: mariadb:latest
  • Volume: db_data (persistent)
  • Port: 3306 (internal)

Redis Service (Cache)

  • Image: redis:alpine (lightweight)
  • Volume: redis_data (persistent)
  • Port: 6379 (internal)
  • Health Check: Built-in Redis ping monitoring
  • Available in all frameworks: Laravel, Symfony, WordPress, OpenCart, Magento2

Network & Volumes

networks:
  app-network:           # Internal communication
    driver: bridge

volumes:
  caddy_data:           # Caddy cache and data
  caddy_config:         # Caddy configuration
  db_data:              # Database persistence

PHP Extensions

Core Extensions

  • Database: pdo_mysql, mysqli
  • String: mbstring, ctype, iconv
  • Data: xml, dom, simplexml, fileinfo
  • Security: openssl, tokenizer
  • Utilities: curl, zip, intl, opcache

Framework-Specific Extensions

All Frameworks (Laravel, Symfony, WordPress, OpenCart, Magento2):

  • redis: Redis cache and session support

Laravel/Magento2:

  • Additional caching optimizations

Symfony:

  • apcu: APCu caching
  • sodium: Modern cryptography

WordPress:

  • Additional compatibility features

Troubleshooting

Port Already in Use

# Change PORT in .env and restart
PORT=8080 docker-compose up -d

Database Connection Issues

Verify credentials in .env:

docker-compose exec php php -r "
\$db = new mysqli('db', 'app', 'secret', 'database');
if (\$db->connect_error) exit('Connection failed: ' . \$db->connect_error);
echo 'Connected successfully!';
"

Permission Issues

# Fix permissions in www directory
chmod -R 755 www/

Rebuild Everything

docker-compose down -v
docker-compose up --build -d

Check Container Status

docker-compose ps
docker-compose logs -f

Useful Commands

# List running containers
docker-compose ps

# Restart a service
docker-compose restart php

# Rebuild images
docker-compose build --no-cache

# Execute command in container
docker-compose exec php <command>

# Copy files from container
docker cp <container>:/path/to/file ./local/path

# View resource usage
docker stats

Performance Optimization

For Production

  1. Set MODE=prod in .env
  2. Enable opcache in php.ini:
    opcache.enable=1
    opcache.memory_consumption=256
    
  3. Configure Redis for caching:
    docker-compose exec php redis-cli
    

Database Optimization

  1. Set appropriate MYSQL_ROOT_PASSWORD
  2. Monitor with:
    docker-compose exec db mysql -u root -p -e "SHOW PROCESSLIST;"
    

Security Best Practices

  • ✅ Change default database credentials in .env
  • ✅ Use strong passwords for MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD_DATABASE
  • ✅ Set MODE=prod for production deployments
  • ✅ Keep php.ini locked to read-only (default)
  • ✅ Use environment variables for sensitive data
  • ✅ Keep Docker images updated

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/improvement)
  3. Make your changes
  4. Test thoroughly
  5. Commit with clear messages (git commit -am 'Add improvement')
  6. Push to your fork (git push origin feature/improvement)
  7. Open a Pull Request

License

[Specify your license here]

Support & Resources

Changelog

v1.1.0 (Current)

  • Multi-stage Docker build for framework-specific optimization
  • Node.js v20.x integration
  • Support for 5+ PHP frameworks with dedicated configurations
  • Improved documentation and examples
  • Production mode with automatic HTTPS

v1.0.0

  • Initial release with FrankenPHP and MariaDB
  • Basic framework support
  • Development and production modes

Last Updated: March 2026
Maintainer: Development Team