diff --git a/README.md b/README.md index 5d62c65..1333f73 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,37 @@ aws ecs update-service --cluster $CLUSTER --service $(terraform output -raw ecs_ ## Configuration Guide +### Application Server Mode + +Choose between **PHP-FPM** (default) or **Laravel Octane** with your preferred driver: + +```hcl +# Traditional PHP-FPM with Nginx (default, most compatible) +app_server_mode = "php-fpm" + +# Laravel Octane with Swoole (battle-tested, excellent performance) +app_server_mode = "octane-swoole" + +# Laravel Octane with RoadRunner (Go-based, great for long-running tasks) +app_server_mode = "octane-roadrunner" + +# Laravel Octane with FrankenPHP (modern, includes Early Hints support) +app_server_mode = "octane-frankenphp" +``` + +**Octane Driver Comparison:** +- **Swoole**: Battle-tested, excellent performance, requires Swoole PHP extension +- **RoadRunner**: Go-based server, great for long-running tasks, excellent stability +- **FrankenPHP**: Modern PHP app server built on Caddy, supports Early Hints and modern HTTP features + +**Laravel Octane Benefits:** +- 2-5x better request throughput +- Lower latency for API responses +- Reduced memory usage per request +- Better for high-traffic applications + +**Important:** Ensure your Laravel application is installed with the Octane package and is compatible with Octane (no global state, stateless services). See [Laravel Octane documentation](https://laravel.com/docs/octane) for details. + ### Minimal Configuration For a basic setup (good for staging/development): @@ -167,6 +198,9 @@ github_repo = "your-repo" app_db_password = "..." db_reporting_password = "..." +# Application server mode +app_server_mode = "php-fpm" # or "octane-swoole", "octane-roadrunner", or "octane-frankenphp" for better performance + # Small instance sizes container_cpu = 512 container_memory = 1024 @@ -201,6 +235,9 @@ github_repo = "your-repo" app_db_password = "..." db_reporting_password = "..." +# Use Laravel Octane for better performance in production (choose your preferred driver) +app_server_mode = "octane-swoole" # or "octane-roadrunner" or "octane-frankenphp" + # Larger instance sizes container_cpu = 2048 container_memory = 4096 @@ -230,6 +267,110 @@ healthcheck_alarm_emails = ["ops@example.com"] **Estimated cost**: ~$300-500/month +## Switching Between PHP-FPM and Octane + +You can switch between PHP-FPM and Laravel Octane (with any driver) at any time by updating your Terraform configuration: + +### Prerequisites for Octane + +Before switching to Octane, ensure your Laravel application: + +1. **Has Laravel Octane installed:** + ```bash + composer require laravel/octane + + # Install your preferred server + php artisan octane:install --server=swoole # For Swoole + php artisan octane:install --server=roadrunner # For RoadRunner + php artisan octane:install --server=frankenphp # For FrankenPHP + ``` + +2. **Is Octane-compatible:** + - No reliance on global state or static variables + - Uses dependency injection properly + - Stateless service classes + - See [Laravel Octane documentation](https://laravel.com/docs/octane#introduction) for details + +### Switching to Octane + +1. Update your `.tfvars` file with your preferred driver: + ```hcl + app_server_mode = "octane-swoole" # Most battle-tested + # OR + app_server_mode = "octane-roadrunner" # Great for long-running tasks + # OR + app_server_mode = "octane-frankenphp" # Modern with Early Hints support + ``` + +2. Apply the Terraform changes: + ```bash + terraform apply -var-file="environments/production.tfvars" + ``` + +3. Deploy your updated Docker image (with Octane installed) and force a new ECS deployment: + ```bash + # The new tasks will automatically start with your chosen Octane driver + aws ecs update-service --cluster $CLUSTER --service $(terraform output -raw ecs_service_name) --force-new-deployment + ``` + +### Switching Back to PHP-FPM + +If you need to revert to PHP-FPM: + +1. Update your `.tfvars` file: + ```hcl + app_server_mode = "php-fpm" + ``` + +2. Apply the Terraform changes and redeploy: + ```bash + terraform apply -var-file="environments/production.tfvars" + aws ecs update-service --cluster $CLUSTER --service $(terraform output -raw ecs_service_name) --force-new-deployment + ``` + +### Testing Your Configuration + +Test Octane locally before deploying to production: + +```bash +# Build and run locally with Octane +docker build -f docker/Dockerfile -t myapp . + +# Generate an APP_KEY first (use an existing Laravel project or Docker) +# Option 1: From your Laravel project directory +APP_KEY=$(php artisan key:generate --show) + +# Option 2: Or generate inside a temporary container +APP_KEY=$(docker run --rm myapp php artisan key:generate --show) + +# Run with Octane Swoole +docker run -p 8080:80 \ + -e APP_ENV=local \ + -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=octane-swoole \ + -e APP_KEY=$APP_KEY \ + myapp + +# Or run with Octane RoadRunner +docker run -p 8080:80 \ + -e APP_ENV=local \ + -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=octane-roadrunner \ + -e APP_KEY=$APP_KEY \ + myapp + +# Or run with Octane FrankenPHP +docker run -p 8080:80 \ + -e APP_ENV=local \ + -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=octane-frankenphp \ + -e APP_KEY=$APP_KEY \ + myapp + +# Test in browser +curl http://localhost:8080 +``` + ## Optional Features ### Enable Meilisearch (Search Engine) diff --git a/docker/Dockerfile b/docker/Dockerfile index 1af6c0a..fce9eba 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -53,9 +53,9 @@ RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ zip \ pcntl \ sockets \ - # PECL - && pecl install redis \ - && docker-php-ext-enable redis \ + # PECL - Install redis and swoole (for Laravel Octane with Swoole) + && pecl install redis swoole \ + && docker-php-ext-enable redis swoole \ # Cleanup after PHP extensions are built && apk del build-base autoconf automake libtool nasm git \ && rm -rf /var/cache/apk/* /tmp/* /var/tmp/* @@ -126,6 +126,16 @@ RUN CACHE_STORE=array php -d memory_limit=512M artisan event:cache --no-interact CACHE_STORE=array php -d memory_limit=512M artisan icons:cache --no-interaction --no-ansi && \ CACHE_STORE=array php -d memory_limit=512M artisan filament:cache-components --no-interaction --no-ansi +# Download RoadRunner binary for Laravel Octane +RUN curl -sSL https://github.com/roadrunner-server/roadrunner/releases/download/v2024.2.1/roadrunner-2024.2.1-linux-amd64.tar.gz \ + | tar -xz -C /usr/local/bin roadrunner && \ + chmod +x /usr/local/bin/roadrunner + +# Download FrankenPHP binary for Laravel Octane +RUN curl -sSL https://github.com/dunglas/frankenphp/releases/download/v1.3.5/frankenphp-linux-x86_64 \ + -o /usr/local/bin/frankenphp && \ + chmod +x /usr/local/bin/frankenphp + # ======================================== # Stage 3: Final application image # ======================================== @@ -137,23 +147,32 @@ WORKDIR /var/www/html # Copy built application from the builder stage COPY --from=builder --chown=www-data:www-data /var/www/html . +# Copy Octane binaries from builder stage +COPY --from=builder /usr/local/bin/roadrunner /usr/local/bin/roadrunner +COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp + # Copy configuration files COPY docker/.profile /root/.profile COPY --chown=www-data:www-data docker/nginx/ /etc/nginx COPY docker/php/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf COPY docker/php/php.ini /usr/local/etc/php/conf.d/99-custom.ini COPY docker/supervisord-web.conf /etc/supervisor/conf.d/supervisord-web.conf +COPY docker/supervisord-web-octane-swoole.conf /etc/supervisor/conf.d/supervisord-web-octane-swoole.conf +COPY docker/supervisord-web-octane-roadrunner.conf /etc/supervisor/conf.d/supervisord-web-octane-roadrunner.conf +COPY docker/supervisord-web-octane-frankenphp.conf /etc/supervisor/conf.d/supervisord-web-octane-frankenphp.conf COPY docker/supervisord-queue-worker.conf /etc/supervisor/conf.d/supervisord-queue-worker.conf COPY docker/supervisord-scheduler.conf /etc/supervisor/conf.d/supervisord-scheduler.conf COPY docker/entrypoint.sh /entrypoint.sh # Make entrypoint executable and create supervisor log directory +# Disable Octane config by default (will be enabled by entrypoint.sh if APP_SERVER_MODE=octane) RUN chmod +x /entrypoint.sh \ && mkdir -p /var/log/supervisor \ && mkdir -p /var/www/html/storage /var/www/html/bootstrap/cache \ && chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache \ && chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache \ && chown -R www-data:www-data /etc/nginx/custom.d \ + && mv /etc/nginx/custom.d/laravel-octane.conf /etc/nginx/custom.d/.laravel-octane.conf \ && mkdir -p /var/lib/nginx/tmp/client_body \ /var/lib/nginx/tmp/proxy \ /var/lib/nginx/tmp/fastcgi \ diff --git a/docker/README.md b/docker/README.md index a059a83..85b3c2e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -2,10 +2,36 @@ This Docker image supports multiple container roles via the `CONTAINER_ROLE` environment variable: -- **web** (default): Runs nginx + php-fpm to serve the web application +- **web** (default): Runs nginx + php-fpm (or Laravel Octane) to serve the web application - **queue-worker**: Runs Laravel queue workers to process SQS jobs - **scheduler**: Runs Laravel scheduler to dispatch scheduled tasks +## Application Server Mode + +The **web** container role supports multiple modes via the `APP_SERVER_MODE` environment variable: + +- **php-fpm** (default): Traditional PHP-FPM with Nginx as FastCGI proxy + - Most compatible with all Laravel applications + - Battle-tested and stable + - Good for applications with moderate traffic + +- **octane-swoole**: Laravel Octane with Swoole and Nginx as reverse proxy + - 2-5x better performance and throughput + - Battle-tested Octane driver with excellent performance + - Requires Swoole PHP extension (included in image) + +- **octane-roadrunner**: Laravel Octane with RoadRunner and Nginx as reverse proxy + - Go-based server with excellent stability + - Great for long-running tasks and memory management + - RoadRunner binary included in image + +- **octane-frankenphp**: Laravel Octane with FrankenPHP and Nginx as reverse proxy + - Modern PHP app server built on Caddy + - Supports Early Hints and modern HTTP features + - FrankenPHP binary included in image + +All Octane modes require Laravel 8+ with Octane package installed and an Octane-compatible application (no global state). + ## Architecture The ECS deployment consists of three separate services: @@ -25,10 +51,35 @@ This separation ensures: # Build the container docker build -f docker/Dockerfile -t laravel-local . -# Run web server locally +# Run web server locally with PHP-FPM (default) +docker run -p 8080:80 \ + -e APP_ENV=local \ + -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=php-fpm \ + -e APP_KEY=base64:$(php artisan key:generate --show) \ + laravel-local + +# Run web server locally with Laravel Octane (Swoole) +docker run -p 8080:80 \ + -e APP_ENV=local \ + -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=octane-swoole \ + -e APP_KEY=base64:$(php artisan key:generate --show) \ + laravel-local + +# Run web server locally with Laravel Octane (RoadRunner) +docker run -p 8080:80 \ + -e APP_ENV=local \ + -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=octane-roadrunner \ + -e APP_KEY=base64:$(php artisan key:generate --show) \ + laravel-local + +# Run web server locally with Laravel Octane (FrankenPHP) docker run -p 8080:80 \ -e APP_ENV=local \ -e CONTAINER_ROLE=web \ + -e APP_SERVER_MODE=octane-frankenphp \ -e APP_KEY=base64:$(php artisan key:generate --show) \ laravel-local diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index a3692b1..69d74f5 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -11,6 +11,9 @@ set -e # This can be set via environment variable CONTAINER_ROLE CONTAINER_ROLE=${CONTAINER_ROLE:-web} +# Determine application server mode (php-fpm or octane) +APP_SERVER_MODE=${APP_SERVER_MODE:-php-fpm} + # Create .env file from .env.example if it doesn't exist if [ ! -f /var/www/html/.env ]; then echo "Creating .env file from .env.example..." @@ -47,8 +50,53 @@ php artisan config:cache --no-interaction || true # Select the appropriate supervisord config based on container role case "$CONTAINER_ROLE" in web) - echo "Starting web server..." - SUPERVISOR_CONF="/etc/supervisor/conf.d/supervisord-web.conf" + # Select web server config based on APP_SERVER_MODE + case "$APP_SERVER_MODE" in + octane-swoole) + echo "Starting web server with Laravel Octane (Swoole)..." + SUPERVISOR_CONF="/etc/supervisor/conf.d/supervisord-web-octane-swoole.conf" + # Swap nginx config to use Octane reverse proxy + if [ -f /etc/nginx/custom.d/laravel.conf ]; then + mv /etc/nginx/custom.d/laravel.conf /etc/nginx/custom.d/.laravel.conf.disabled + fi + if [ -f /etc/nginx/custom.d/.laravel-octane.conf ]; then + mv /etc/nginx/custom.d/.laravel-octane.conf /etc/nginx/custom.d/laravel-octane.conf + fi + ;; + octane-roadrunner) + echo "Starting web server with Laravel Octane (RoadRunner)..." + SUPERVISOR_CONF="/etc/supervisor/conf.d/supervisord-web-octane-roadrunner.conf" + # Swap nginx config to use Octane reverse proxy + if [ -f /etc/nginx/custom.d/laravel.conf ]; then + mv /etc/nginx/custom.d/laravel.conf /etc/nginx/custom.d/.laravel.conf.disabled + fi + if [ -f /etc/nginx/custom.d/.laravel-octane.conf ]; then + mv /etc/nginx/custom.d/.laravel-octane.conf /etc/nginx/custom.d/laravel-octane.conf + fi + ;; + octane-frankenphp) + echo "Starting web server with Laravel Octane (FrankenPHP)..." + SUPERVISOR_CONF="/etc/supervisor/conf.d/supervisord-web-octane-frankenphp.conf" + # Swap nginx config to use Octane reverse proxy + if [ -f /etc/nginx/custom.d/laravel.conf ]; then + mv /etc/nginx/custom.d/laravel.conf /etc/nginx/custom.d/.laravel.conf.disabled + fi + if [ -f /etc/nginx/custom.d/.laravel-octane.conf ]; then + mv /etc/nginx/custom.d/.laravel-octane.conf /etc/nginx/custom.d/laravel-octane.conf + fi + ;; + php-fpm|*) + echo "Starting web server with PHP-FPM..." + SUPERVISOR_CONF="/etc/supervisor/conf.d/supervisord-web.conf" + # Ensure PHP-FPM config is active + if [ -f /etc/nginx/custom.d/.laravel.conf.disabled ]; then + mv /etc/nginx/custom.d/.laravel.conf.disabled /etc/nginx/custom.d/laravel.conf + fi + if [ -f /etc/nginx/custom.d/laravel-octane.conf ]; then + mv /etc/nginx/custom.d/laravel-octane.conf /etc/nginx/custom.d/.laravel-octane.conf + fi + ;; + esac ;; queue-worker) echo "Starting queue worker..." diff --git a/docker/nginx/custom.d/laravel-octane.conf b/docker/nginx/custom.d/laravel-octane.conf new file mode 100644 index 0000000..6643b88 --- /dev/null +++ b/docker/nginx/custom.d/laravel-octane.conf @@ -0,0 +1,30 @@ +index index.php index.html index.htm; + +# Increase upload size limit +client_max_body_size 32M; + +# Set real IP from ALB +real_ip_header X-Forwarded-For; +set_real_ip_from 10.0.0.0/8; +real_ip_recursive on; + +# Proxy all requests to Laravel Octane +location / { + proxy_pass http://127.0.0.1:8000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Pass ALB headers to Octane/Laravel + proxy_set_header X-Forwarded-Host $host; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; +} diff --git a/docker/supervisord-web-octane-frankenphp.conf b/docker/supervisord-web-octane-frankenphp.conf new file mode 100644 index 0000000..ed2d060 --- /dev/null +++ b/docker/supervisord-web-octane-frankenphp.conf @@ -0,0 +1,28 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:nginx] +command=nginx -g "daemon off;" +priority=20 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +startretries=3 +startsecs=5 + +[program:octane] +command=php /var/www/html/artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000 --workers=auto --max-requests=500 +priority=10 +user=www-data +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +startretries=3 +startsecs=5 diff --git a/docker/supervisord-web-octane-roadrunner.conf b/docker/supervisord-web-octane-roadrunner.conf new file mode 100644 index 0000000..e8ef919 --- /dev/null +++ b/docker/supervisord-web-octane-roadrunner.conf @@ -0,0 +1,28 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:nginx] +command=nginx -g "daemon off;" +priority=20 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +startretries=3 +startsecs=5 + +[program:octane] +command=php /var/www/html/artisan octane:start --server=roadrunner --host=127.0.0.1 --port=8000 --workers=auto --max-requests=500 +priority=10 +user=www-data +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +startretries=3 +startsecs=5 diff --git a/docker/supervisord-web-octane-swoole.conf b/docker/supervisord-web-octane-swoole.conf new file mode 100644 index 0000000..eaec058 --- /dev/null +++ b/docker/supervisord-web-octane-swoole.conf @@ -0,0 +1,28 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:nginx] +command=nginx -g "daemon off;" +priority=20 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +startretries=3 +startsecs=5 + +[program:octane] +command=php /var/www/html/artisan octane:start --host=127.0.0.1 --port=8000 --workers=auto --max-requests=500 +priority=10 +user=www-data +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +startretries=3 +startsecs=5 diff --git a/terraform/environments/example.tfvars b/terraform/environments/example.tfvars index 58a7a43..e008376 100644 --- a/terraform/environments/example.tfvars +++ b/terraform/environments/example.tfvars @@ -64,24 +64,34 @@ meilisearch_master_key = "CHANGE_ME_MEILISEARCH_KEY" # CPU 2048: 4096 to 16384 (1GB increments) # CPU 4096: 8192 to 30720 (1GB increments) +# Application server mode: "php-fpm" (default), "octane-swoole", "octane-roadrunner", or "octane-frankenphp" +# Laravel Octane provides significantly better performance by keeping the application +# in memory and serving requests through various high-performance servers. +# - php-fpm: Traditional PHP-FPM (most compatible) +# - octane-swoole: Octane with Swoole (battle-tested, excellent performance) +# - octane-roadrunner: Octane with RoadRunner (Go-based, great for long-running tasks) +# - octane-frankenphp: Octane with FrankenPHP (modern, includes Early Hints support) +# Requires Laravel 8+ with Octane installed and an Octane-compatible application (no global state). +app_server_mode = "php-fpm" + # Web Service (handles HTTP requests) -container_cpu = 1024 # CPU units (1024 = 1 vCPU) -container_memory = 2048 # Memory in MB +container_cpu = 1024 # CPU units (1024 = 1 vCPU) +container_memory = 2048 # Memory in MB # Web service scaling configuration -desired_count = 2 # Number of tasks to run -min_capacity = 1 # Minimum tasks for auto-scaling -max_capacity = 10 # Maximum tasks for auto-scaling +desired_count = 2 # Number of tasks to run +min_capacity = 1 # Minimum tasks for auto-scaling +max_capacity = 10 # Maximum tasks for auto-scaling # Queue Worker (processes background jobs) -queue_worker_cpu = 512 # CPU units (512 = 0.5 vCPU) -queue_worker_memory = 1024 # Memory in MB -queue_worker_desired_count = 1 # Number of queue worker tasks +queue_worker_cpu = 512 # CPU units (512 = 0.5 vCPU) +queue_worker_memory = 1024 # Memory in MB +queue_worker_desired_count = 1 # Number of queue worker tasks # Scheduler (runs Laravel's cron/scheduled tasks) -scheduler_cpu = 256 # CPU units (256 = 0.25 vCPU) -scheduler_memory = 512 # Memory in MB -scheduler_desired_count = 1 # Number of scheduler tasks (typically 1) +scheduler_cpu = 256 # CPU units (256 = 0.25 vCPU) +scheduler_memory = 512 # Memory in MB +scheduler_desired_count = 1 # Number of scheduler tasks (typically 1) # ======================================== # Database Configuration diff --git a/terraform/main.tf b/terraform/main.tf index 0664b33..c65b566 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -217,21 +217,21 @@ module "compute" { source = "./modules/compute" depends_on = [module.load_balancer] - app_name = var.app_name - environment = var.environment - aws_region = var.aws_region - domain_name = var.domain_name - vpc_id = module.networking.vpc_id - private_subnets = module.networking.private_subnets - ecs_security_group_id = module.networking.ecs_security_group_id - target_group_arn = module.load_balancer.target_group_arn - ecr_repository_url = module.container_registry.repository_url - ecs_execution_role_arn = module.security.ecs_execution_role_arn - ecs_task_role_arn = module.security.ecs_task_role_arn - log_group_name = module.monitoring.log_group_name - s3_filesystem_bucket_name = module.storage.app_filesystem_bucket_name - sqs_queue_name = module.messaging.queue_name - caller_identity_account_id = data.aws_caller_identity.current.account_id + app_name = var.app_name + environment = var.environment + aws_region = var.aws_region + domain_name = var.domain_name + vpc_id = module.networking.vpc_id + private_subnets = module.networking.private_subnets + ecs_security_group_id = module.networking.ecs_security_group_id + target_group_arn = module.load_balancer.target_group_arn + ecr_repository_url = module.container_registry.repository_url + ecs_execution_role_arn = module.security.ecs_execution_role_arn + ecs_task_role_arn = module.security.ecs_task_role_arn + log_group_name = module.monitoring.log_group_name + s3_filesystem_bucket_name = module.storage.app_filesystem_bucket_name + sqs_queue_name = module.messaging.queue_name + caller_identity_account_id = data.aws_caller_identity.current.account_id # Web service configuration container_cpu = var.container_cpu @@ -254,6 +254,7 @@ module "compute" { meilisearch_master_key = var.enable_meilisearch ? var.meilisearch_master_key : "" redis_endpoint = module.cache.redis_endpoint redis_port = module.cache.redis_port + app_server_mode = var.app_server_mode additional_environment_variables = var.additional_environment_variables common_tags = local.common_tags } diff --git a/terraform/modules/compute/main.tf b/terraform/modules/compute/main.tf index 80b7e74..826719e 100644 --- a/terraform/modules/compute/main.tf +++ b/terraform/modules/compute/main.tf @@ -17,6 +17,10 @@ locals { name = "APP_URL" value = "https://${var.domain_name}" }, + { + name = "APP_SERVER_MODE" + value = var.app_server_mode + }, { name = "REDIS_HOST" value = var.redis_endpoint diff --git a/terraform/modules/compute/variables.tf b/terraform/modules/compute/variables.tf index 3da3490..eb26a84 100644 --- a/terraform/modules/compute/variables.tf +++ b/terraform/modules/compute/variables.tf @@ -197,3 +197,9 @@ variable "enable_scheduler" { type = bool default = true } + +variable "app_server_mode" { + description = "Application server mode. Valid values: 'php-fpm', 'octane-swoole', 'octane-roadrunner', and 'octane-frankenphp'." + type = string + default = "php-fpm" +} diff --git a/terraform/variables.tf b/terraform/variables.tf index 88a30af..b679b5b 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -102,6 +102,17 @@ variable "max_capacity" { default = 10 } +# Application Server Mode +variable "app_server_mode" { + description = "Application server mode: 'php-fpm' (default), 'octane-swoole', 'octane-frankenphp', or 'octane-roadrunner'. Octane modes provide better performance for Laravel applications." + type = string + default = "php-fpm" + validation { + condition = contains(["php-fpm", "octane-swoole", "octane-frankenphp", "octane-roadrunner"], var.app_server_mode) + error_message = "app_server_mode must be one of: 'php-fpm', 'octane-swoole', 'octane-frankenphp', or 'octane-roadrunner'" + } +} + # Queue Worker (processes background jobs) variable "queue_worker_cpu" { description = "CPU units for the queue worker container (256 = 0.25 vCPU, 512 = 0.5 vCPU, 1024 = 1 vCPU)"