
September 09, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Production teams outgrow manual SSH deploys fast. CI/CD on AWS with CodePipeline, CodeBuild and CodeDeploy gives you a managed path from Git push to running code on EC2 without babysitting every release. If you already run Laravel on AWS, as covered in our Laravel on AWS EC2 with RDS guide, these three services slot cleanly into that stack. This walkthrough covers IAM, buildspec files, pipeline stages, and CodeDeploy hooks you can copy today.
What is CI/CD on AWS with CodePipeline, CodeBuild and CodeDeploy?
Think of the trio as three specialised layers. CodePipeline is the conductor. It watches your repository, runs stages in order, and passes artifacts between them. CodeBuild is the compile-and-test worker. It spins up containers from a buildspec file, runs Composer, npm, PHPUnit, and packages output. CodeDeploy is the release engine on your servers. It copies files, runs lifecycle hooks, and rolls back if health checks fail.
On real client projects I have maintained sister legal-tech sites on shared EC2 using GitLab CI and Deployer 7. AWS-native CI/CD fits the same mental model: build once, deploy the same artifact everywhere, reload PHP-FPM after the symlink swap. The difference is AWS owns the runners and orchestration. You pay per build minute instead of patching a Jenkins box.
Each service has a narrow job. That separation keeps pipelines readable and lets you swap the source provider without rewriting deploy logic. CodePipeline supports GitHub, GitLab, Bitbucket, and CodeCommit as sources. Most teams I work with connect an existing GitHub repo through a CodeStar connection.
How the three services compare to self-hosted CI
| Criteria | CodePipeline + CodeBuild + CodeDeploy | Self-hosted (Jenkins / GitLab Runner) |
|---|---|---|
| Runner maintenance | AWS-managed build fleet | You patch OS, Docker, and agents |
| Cost model | Per build minute + pipeline stage | Fixed EC2 cost even when idle |
| EC2 deploy integration | Native CodeDeploy agent and hooks | Custom SSH or Deployer scripts |
| Secret storage | Secrets Manager / SSM Parameter Store | CI variables, often duplicated |
| Best fit | Teams already on AWS EC2/ASG | Multi-cloud or strict on-prem needs |
If you are weighing hosts first, read our AWS vs DigitalOcean vs Hetzner for Laravel hosting comparison. AWS CI/CD pays off when your compute and database already live in the same account and VPC.
How do you set up a CodePipeline for a Laravel application?
Start with IAM roles before you click through the console wizard. CodePipeline needs a service role that trusts codepipeline.amazonaws.com. CodeBuild needs its own role with CloudWatch Logs, S3 artifact read/write, and Secrets Manager access. CodeDeploy needs a role on the EC2 instance profile so the agent can pull revisions from S3.
A typical Laravel pipeline on PHP 8.3 or 8.5 with Laravel 12 or 13.x has four stages:
- Source — trigger on push to
mainor on tag. - Build — CodeBuild runs tests, compiles front-end assets with Node.js 26 LTS and npm 12, outputs a zip.
- Deploy (staging) — CodeDeploy to a staging Auto Scaling group.
- Deploy (production) — manual approval gate, then CodeDeploy to production.
Provision baseline infrastructure with CloudFormation or Terraform first. Our CloudFormation on AWS guide covers stack patterns that pair well with pipeline-driven deploys. The pipeline should not create EC2 instances on every run. It should deploy new application revisions to an existing fleet.
Create the pipeline via AWS CLI
aws codepipeline create-pipeline --cli-input-json file://pipeline.json A minimal pipeline.json skeleton references your CodeBuild project and CodeDeploy application:
{
"pipeline": {
"name": "laravel-production",
"roleArn": "arn:aws:iam::123456789012:role/CodePipelineServiceRole",
"artifactStore": {
"type": "S3",
"location": "my-company-pipeline-artifacts"
},
"stages": [
{
"name": "Source",
"actions": [{
"name": "GitHub",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "CodeStarSourceConnection",
"version": "1"
},
"configuration": {
"ConnectionArn": "arn:aws:codestar-connections:...",
"FullRepositoryId": "org/laravel-app",
"BranchName": "main"
},
"outputArtifacts": [{"name": "SourceOutput"}]
}]
},
{
"name": "Build",
"actions": [{
"name": "BuildAndTest",
"actionTypeId": {
"category": "Build",
"owner": "AWS",
"provider": "CodeBuild",
"version": "1"
},
"configuration": {
"ProjectName": "laravel-build"
},
"inputArtifacts": [{"name": "SourceOutput"}],
"outputArtifacts": [{"name": "BuildOutput"}]
}]
},
{
"name": "Deploy",
"actions": [{
"name": "DeployProduction",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"provider": "CodeDeploy",
"version": "1"
},
"configuration": {
"ApplicationName": "laravel-app",
"DeploymentGroupName": "production-asg"
},
"inputArtifacts": [{"name": "BuildOutput"}]
}]
}
]
}
} Store database credentials in Secrets Manager, not in the buildspec. See manage secrets with AWS Secrets Manager and our broader CI/CD secrets management best practices article for rotation patterns.
What should you put in a CodeBuild buildspec.yml file?
CodeBuild reads buildspec.yml from your repository root by default. Version 0.2 is the current format. Define install, pre_build, build, and post_build phases explicitly. Cache Composer and npm directories to cut build times. Our CI/CD caching for Composer and npm guide applies the same principles inside CodeBuild cache paths.
version: 0.2
env:
secrets-manager:
DB_PASSWORD: prod/laravel:password
phases:
install:
runtime-versions:
php: 8.3
nodejs: 26
commands:
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer --version
pre_build:
commands:
- cp .env.ci .env
- composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
- npm ci
build:
commands:
- php artisan config:clear
- npm run build
- vendor/bin/phpunit --colors=never
post_build:
commands:
- rm -rf node_modules tests .git
- zip -r app.zip . -x "*.env*"
artifacts:
files:
- app.zip
name: laravel-build
cache:
paths:
- vendor//*
- node_modules//* Pin your PHP runtime in the CodeBuild project if you need 8.5. The console image may lag the anchor release. For Laravel 13.x you need PHP 8.3 minimum. Laravel 12 runs on PHP 8.2 or higher. Match the runtime on EC2 and in CodeBuild or you will chase extension mismatch bugs.
Fail builds on low test coverage
Add a coverage gate when the project warrants it. PHPUnit can emit Clover XML and you fail the build if coverage drops. Details sit in our code coverage gates in CI post. CodeBuild exposes CODEBUILD_BUILD_SUCCEEDING so post_build scripts can exit non-zero and mark the stage failed.
Validate buildspec syntax with the JSON formatter tool when you embed complex environment blocks. A trailing comma in inline JSON breaks the whole pipeline at create time.
Official reference: the AWS CodeBuild build specification reference lists every supported key and phase hook.
How does CodeDeploy work with EC2 and in-place vs blue/green?
CodeDeploy installs a lightweight agent on each EC2 instance. The agent polls for new deployments tied to a deployment group. You register instances by tag or Auto Scaling group membership. Each deployment follows instructions in appspec.yml at the root of your artifact zip.
version: 0.0
os: linux
files:
- source: /
destination: /var/www/laravel
permissions:
- object: /var/www/laravel
pattern: "**"
owner: www-data
group: www-data
hooks:
BeforeInstall:
- location: scripts/stop.sh
timeout: 120
AfterInstall:
- location: scripts/migrate.sh
timeout: 300
ApplicationStart:
- location: scripts/start.sh
timeout: 120 Hook scripts live beside appspec in your repo. Keep them idempotent. A common pattern I've used on production Laravel applications:
- BeforeInstall — put app in maintenance mode, drain queues.
- AfterInstall — run
php artisan migrate --force, clear caches. - ApplicationStart — reload PHP-FPM, disable maintenance mode.
CodeDeploy supports two compute platforms: EC2/on-premises and Lambda. For web apps on ASG, EC2 is the usual choice. Deployment configs control rollout speed:
| Config | Behaviour | When to use |
|---|---|---|
| OneAtATime | Single instance update, waits for success | Small fleets, low traffic |
| HalfAtATime | 50% concurrent updates | Medium ASG, acceptable brief capacity drop |
| AllAtOnce | Every instance simultaneously | Staging only — never production |
| Blue/Green via ASG | New target group, traffic shift, tear down old | Zero-downtime production releases |
Blue/green on AWS pairs CodeDeploy with a second target group and an Application Load Balancer listener rule swap. The concept matches what we describe in CI/CD blue/green deployment explained. In-place deploys are simpler but briefly mix old and new code on different nodes. That can surface cache and schema race conditions.
Install the CodeDeploy agent on Ubuntu 22.04 or 24.04 during AMI bake or user-data bootstrap. Verify with sudo service codedeploy-agent status. A missing agent is the number-one reason deploy stages hang at "In Progress". Official docs: CodeDeploy agent installation guide.
What are common CI/CD on AWS mistakes and how do you fix them?
Most failed pipelines I troubleshoot are IAM or path problems, not AWS bugs. The build succeeds, the deploy stage red bar appears, and someone SSHs in to fix it manually. That defeats the purpose of automation.
IAM and artifact path errors
CodeBuild must write to the artifact bucket. CodeDeploy must read from it. The EC2 instance role needs s3:GetObject on that bucket prefix. CodePipeline passes artifact names between stages. A typo in outputArtifacts or inputArtifacts gives you an empty zip on the deploy box.
Stale PHP opcache after deploy
Laravel on EC2 often runs PHP-FPM with opcache enabled. Copying new files does not reload workers. Your ApplicationStart hook should run sudo systemctl reload php8.3-fpm. I have seen this during production deployments on sister sites sharing a Deployer workflow. The same fix applies to CodeDeploy hooks.
Building assets on the server
Do not run npm on production EC2 unless you enjoy 512 MB instances swapping to death. Build front-end assets in CodeBuild with Vite 8.x and ship public/build inside the artifact. This mirrors the pattern in our GitLab CI pipeline for Laravel guide.
Skipping smoke tests post-deploy
Add a Lambda or CodeBuild post-deploy action that curls /health or runs an HTTP check against the ALB. Failing fast triggers automatic rollback via CloudWatch alarm on 5xx rate. Small teams benefit from the checklist in CI/CD best practices for small teams.
Automate repetitive fixes with Boto3 scripts triggered from EventBridge when a pipeline state changes. Our automate AWS with Boto3 tutorial shows how to list failed executions and post to Slack.
For ongoing ops after go-live, pair the pipeline with support and maintenance services or Linux system administration so someone watches alarms and monthly AWS bills. Several sites on my shared EC2 pipeline — including work visible in our Notary Kathmandu portfolio case and Adventure Third Pole Trek booking platform — rely on disciplined deploy hooks rather than heroic midnight SSH sessions.
If you prefer VPS plus GitLab over native AWS tooling, the deploy Laravel with GitLab CI to a VPS guide is the closest alternative. Compare pipeline setup approaches in CI/CD pipeline setup for Nepal teams before committing to one vendor stack.
Scan commits for leaked keys before they reach CodeBuild. Pair pipeline secrets with git-level scanning described in secrets scanning in git and CI with Gitleaks. The AWS CodePipeline user guide remains the authoritative map of action providers and stage limits.
Key Takeaways
- Wire IAM roles for CodePipeline, CodeBuild, and the EC2 instance profile before creating the pipeline — half of deploy failures are permission errors.
- Build and test in CodeBuild with a versioned buildspec.yml; ship a zip artifact containing vendor/, compiled assets, and appspec.yml — never run npm on production EC2.
- Use CodeDeploy lifecycle hooks to migrate, cache-clear, and reload PHP-FPM; opcache will otherwise serve stale bytecode after a successful copy.
- Choose blue/green with ALB target group swaps for zero-downtime production; reserve in-place OneAtATime for staging or tiny fleets.
- Store secrets in Secrets Manager, add manual approval before production, and attach post-deploy HTTP health checks to enable automatic rollback.
- Cache Composer and npm directories in CodeBuild to keep per-minute build costs predictable on busy monorepos.
People Also Ask
Does CodePipeline replace Jenkins or GitLab CI entirely?
Not always. CodePipeline excels when your runtime is already on AWS EC2, Lambda, or ECS. Teams on multi-cloud VPS setups often keep GitLab CI or GitHub Actions for build and test, then trigger CodeDeploy through a thin deploy job. The build artifact format stays the same.
How much does AWS CodeBuild cost for a typical Laravel pipeline?
CodeBuild charges per build minute by compute type. A general1.small Linux build with cached dependencies often finishes a Laravel test suite in three to eight minutes. Budget roughly USD 0.005–0.02 per build at 2026 on-demand rates, plus S3 storage for artifacts. Busy teams running twenty builds daily still spend less than a dedicated t3.small Jenkins runner at roughly Rs 3,500/month (~USD 26).
Can CodeDeploy deploy to Lambda or ECS instead of EC2?
Yes. CodeDeploy supports Lambda function versions with traffic shifting and ECS blue/green through codedeploy hooks on task sets. The appspec format differs from EC2. Laravel apps on Lambda typically use Laravel Vapor rather than raw CodeDeploy, but the same pipeline can fan out to multiple deploy actions per environment.
What is the fastest way to roll back a bad CodeDeploy release?
Re-run the pipeline against the last known-good Git tag, or use the CodeDeploy console to redeploy the previous revision already stored in S3. Blue/green setups roll back by shifting the ALB listener back to the old target group without rebuilding. Keep at least five revision history entries in the deployment group configuration.
Ship repeatable releases on AWS
You now have the full path for CI/CD on AWS with CodePipeline, CodeBuild and CodeDeploy: IAM roles, a Laravel buildspec, pipeline stages, appspec hooks, and a deploy strategy that matches your traffic profile. Start with a staging deployment group, prove rollback works, then add the manual approval gate before production. Need hands-on help wiring this to an existing Laravel fleet or migrating from GitLab CI on EC2? Contact us or explore enterprise application development services for a production-ready pipeline audit.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

