A batteries-included, copy-and-ship blueprint for deploying a containerized Laravel application to Amazon ECS (EC2 launch type) behind an Application Load Balancer β with a ready-to-run local development stack and a CI/CD pipeline.
Getting a PHP application onto AWS ECS involves a lot of moving parts β a multi-container task (PHP-FPM + a web server), an image registry, a load balancer with dynamic port mapping, and a deployment pipeline. This repository packages that entire path as a reusable reference architecture you can clone, point at your own AWS account, and deploy.
It ships two production-oriented Docker images (a hardened PHP-FPM app container and an Nginx reverse proxy), a Docker Compose stack that spins up the app, Nginx, MySQL, and Redis locally with one command, an exportable ECS task definition, and a GitLab CI/CD pipeline that builds, pushes to ECR, and rolls out a new task revision.
Who is this for? DevOps and backend engineers who want a known-good, documented pattern for running Laravel on ECS/EC2 instead of assembling it from scratch.
- π³ Two-container architecture β PHP-FPM app + Nginx proxy, communicating over FastCGI, matching AWS's recommended sidecar pattern.
- β‘ One-command local environment β
docker compose upgives you app + Nginx + MySQL 8 + Redis, wired together and ready. - βοΈ ECS on EC2, ALB-ready β task definition uses dynamic host-port mapping so multiple tasks can share an EC2 instance behind an Application Load Balancer.
- π CI/CD included β GitLab pipeline builds both images, pushes to Amazon ECR (immutable +
latesttags), and triggers a zero-downtime ECS service update. - π Security-conscious defaults β non-root container user, least-privilege file permissions,
.envnever committed, and CloudWatch logging pre-wired. - π©Ί Health-check endpoint β a lightweight
/healthroute for ALB target-group checks. - π Fully documented β architecture, deployment, and local-dev guides live in
docs/.
flowchart LR
U[π€ Client] -->|HTTP/HTTPS| ALB[Application Load Balancer]
ALB -->|dynamic port| I[EC2 Container Instance]
subgraph ECS["ECS Task (laravel-app)"]
N["Nginx :80<br/>(reverse proxy)"]
A["PHP-FPM :9000<br/>(Laravel app)"]
N -->|FastCGI| A
end
I --> ECS
A --> DB[(RDS / MySQL)]
A --> R[(ElastiCache / Redis)]
Request flow: the ALB forwards traffic to the Nginx container on a dynamically assigned host port; Nginx serves static files and proxies PHP requests over FastCGI to the PHP-FPM container; the app talks to MySQL and Redis. See docs/ARCHITECTURE.md for the full breakdown.
| Layer | Technology |
|---|---|
| Application | Laravel 8 (PHP 8.1) |
| Web server | Nginx (Alpine) |
| App runtime | PHP-FPM (Alpine) with pdo_mysql, gd, redis, zip, exif, pcntl |
| Local orchestration | Docker Compose (app, nginx, MySQL 8, Redis) |
| Container registry | Amazon ECR |
| Orchestration | Amazon ECS (EC2 launch type) |
| Ingress | Application Load Balancer (dynamic port mapping) |
| CI/CD | GitLab CI |
| Data & cache | MySQL / Amazon RDS, Redis / ElastiCache |
.
βββ Dockerfile # PHP-FPM application image (installs Composer deps)
βββ Dockerfile_Nginx # Nginx reverse-proxy image
βββ docker-compose.yml # Local dev stack: app + nginx + mysql + redis
βββ .dockerignore # Keeps build context (and images) lean
βββ taskdef.json # Exportable ECS task definition (2 containers)
βββ .gitlab-ci.yml # Build β push to ECR β deploy to ECS
βββ Makefile # Shortcuts: make up / build / deploy-vars ...
βββ .env.example # Environment template (copy to .env)
βββ config/
β βββ nginx/conf.d/app.conf # Nginx server block + /health endpoint
β βββ php/local.ini # PHP runtime tuning (upload size, memory)
βββ docs/ # Architecture, deployment & local-dev guides
βββ app/ routes/ ... # Standard Laravel application code
- Docker & Docker Compose v2
- An AWS account with permissions for ECR, ECS, EC2, and ELB (for deployment)
- AWS CLI v2 (for deployment)
# 1. Clone
git clone <your-fork-url> && cd laravel-ecs-ec2
# 2. Create your environment file
cp .env.example .env
# 3. Build and start the full stack (app + nginx + mysql + redis)
docker compose up -d --build
# 4. Generate the app key and run migrations
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrateNow open http://localhost:8080 π
Prefer shortcuts? Run
make upβ see theMakefilefor the full list.
Full walkthrough: docs/LOCAL_DEVELOPMENT.md.
Deployment is fully documented step-by-step in docs/DEPLOYMENT.md. The high-level flow:
- Create two ECR repositories β
laravel-appandlaravel-nginx. - Create an ECS cluster (EC2 launch type) and register the task definition from
taskdef.json. - Provision an Application Load Balancer + target group (dynamic port mapping).
- Create an ECS service attached to the ALB.
- Configure CI/CD variables (below) and push to trigger a build & deploy.
Set these in GitLab β Settings β CI/CD β Variables:
| Variable | Description |
|---|---|
AWS_ACCESS_KEY_ID |
IAM key with ECR/ECS permissions |
AWS_SECRET_ACCESS_KEY |
IAM secret |
AWS_DEFAULT_REGION |
e.g. us-east-1 |
ECR_REGISTRY |
<AWS_ACCOUNT_ID>.dkr.ecr.<AWS_REGION>.amazonaws.com |
ECR_REPOSITORY_APP_IMAGE |
${ECR_REGISTRY}/laravel-app |
ECR_REPOSITORY_NGINX_IMAGE |
${ECR_REGISTRY}/laravel-nginx |
ECS_CLUSTER |
ECS cluster name (e.g. laravel) |
ECS_SERVICE |
ECS service name (e.g. laravel-deployment) |
β οΈ Never commit real credentials or account IDs. All AWS identifiers in this repo are placeholders (<AWS_ACCOUNT_ID>,<AWS_REGION>); supply real values only through CI/CD variables or your local.env(which is git-ignored).
Environment is driven by .env (copy from .env.example). Key values:
| Variable | Purpose | Local default |
|---|---|---|
APP_KEY |
Laravel encryption key (php artisan key:generate) |
β |
DB_HOST / DB_DATABASE / DB_USERNAME / DB_PASSWORD |
Database connection | db / laravel / laravel / secret |
REDIS_HOST |
Redis host | redis |
SESSION_DRIVER / CACHE_DRIVER |
Backed by Redis in the container stack | redis |
APP_PORT |
Host port Nginx binds to locally | 8080 |
The Nginx config exposes a /health endpoint that returns 200 OK without hitting PHP β use it as the ALB target-group health check path:
curl http://localhost:8080/health # -> healthyContributions are welcome! Please read CONTRIBUTING.md before opening a pull request.
Distributed under the MIT License. See LICENSE for details.
Inspired by community patterns for running Laravel on AWS ECS, adapted into a documented, reusable blueprint.