1 A Real-World Cloud Deployment Project
We have covered the theory of cloud computing, datacenters, virtualization, Docker containers, reverse proxies, and backup strategies. The crowning test of a Cloud & DevOps engineer is to synthesize these individual building blocks into an unshakeable, automated production deployment.
Imagine your engineering team has developed a modern web application using Laravel 11, MySQL 8.4, Redis, and Nginx. It works flawlessly on your local laptop at localhost:8000. Now, you must publish it to the internet so thousands of global customers can access it securely, reliably, and with lightning speed.
Novice developers often believe that running git clone on a server completes the job. In production engineering, a robust deployment requires:
- Hardening OS ports and host firewalls so internal databases are never exposed to the public internet.
- Containerizing all runtimes with Docker to eliminate "Works on my machine" inconsistencies.
- Securing web endpoints with Let's Encrypt TLS 1.3 certificates and automated renewal.
- Setting up a GitHub Actions CI/CD pipeline so pushing code triggers tests and deploys zero-downtime updates.
- Decoupling long-running tasks into background asynchronous queue workers.
- Implementing telemetry health checks, automated alerts, and off-site encrypted database backups.
2 Project Technology Stack
Our capstone architecture utilizes industry-standard, battle-tested open-source components:
| Technology | Version / Platform | Role in Architecture |
|---|---|---|
| Laravel | 11.x (PHP 8.3-FPM) | Core backend web application, business domain logic & RESTful APIs |
| MySQL | 8.4 LTS (Official) | Primary relational transactional database (with named persistent Docker volumes) |
| Redis | 7.x Alpine | In-memory caching and persistent asynchronous background queue broker |
| Docker & Compose | v26.x / Compose v2 | Application, web server, database, and background worker containerization |
| Ubuntu Server | 24.04 LTS (Noble) | Cloud Virtual Machine host operating system |
| Nginx Reverse Proxy | 1.24+ (Host & Container) | TLS/SSL termination, edge routing, static asset caching, and FastCGI bridging |
| Let's Encrypt / Certbot | Snap Classic | Automated free 90-day SSL/TLS certificate generation and renewal |
| GitHub Actions & GHCR | CI/CD Runner | Continuous testing, multi-stage Docker image builds, and automated SSH deployment |
3 Master Production Deployment Architecture Blueprint
The complete journey of user requests through the host firewall, reverse proxy, and container network is mapped out below:
Key Security Guarantee: Notice that internal database and runtime ports (MySQL 3306, Redis 6379, PHP-FPM 9000) are never exposed to the public internet. Only the Host Nginx daemon listens on public ports 80 and 443, proxying valid web traffic to Docker's loopback port 127.0.0.1:8080.
4 Step 1: Preparing the Application for Production
Before provisioning cloud hardware, validate application health and enforce production configurations on your local environment:
4.1 Validating Dependencies and Test Suites
4.2 Hardening Production Environment (.env.production)
Leaving APP_DEBUG=true in production is a fatal vulnerability that exposes database credentials and secrets upon any uncaught exception.
5 Step 2: Provisioning Cloud Server & SSH Authentication
Provision an Ubuntu Virtual Machine on AWS EC2, DigitalOcean, Hetzner, or Google Compute Engine:
Connecting and Updating System Packages
6 Step 3: Server Security & UFW Firewall Hardening
Before running any workloads, configure the host firewall to enforce a default-deny policy:
By default, Docker manipulates Linux iptables directly. If you specify ports: "3306:3306" in Docker Compose, Docker injects rules that bypass UFW, exposing your database to the world! Never publish database ports publicly; always bind web containers strictly to 127.0.0.1:8080:80.
7 Step 4: Installing Docker Engine & Docker Compose
Install the official Docker Engine and Docker Compose v2 plugin on Ubuntu:
Creating Production Application Directory
8 Step 5: Production Docker Compose Configuration
Our production /opt/myapp/compose.yaml configures five orchestrated microservices:
services:
# 1. Laravel PHP 8.3-FPM Application Core
app:
image: ghcr.io/byteionlab/myapp-php:${IMAGE_TAG}
restart: unless-stopped
env_file:
- .env.production
expose:
- "9000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- laravel_storage:/var/www/html/storage
networks:
- backend
# 2. Container Nginx Web Server
web:
image: ghcr.io/byteionlab/myapp-nginx:${IMAGE_TAG}
restart: unless-stopped
ports:
- "127.0.0.1:8080:80" # Bound exclusively to host loopback interface
depends_on:
- app
networks:
- backend
# 3. Laravel Background Queue Worker
worker:
image: ghcr.io/byteionlab/myapp-php:${IMAGE_TAG}
restart: unless-stopped
env_file:
- .env.production
command: ["php", "artisan", "queue:work", "--sleep=3", "--tries=3", "--timeout=90"]
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- laravel_storage:/var/www/html/storage
networks:
- backend
# 4. MySQL 8.4 Relational Database Server
db:
image: mysql:8.4
restart: unless-stopped
env_file:
- .env.mysql
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u root -p$$MYSQL_ROOT_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# 5. Redis In-Memory Cache & Queue Store
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis_data:/data
networks:
- backend
volumes:
mysql_data:
redis_data:
laravel_storage:
networks:
backend:
driver: bridge
Restrict permissions on .env.production and .env.mysql so only the deployer user can read them:
9 Step 6: Container Nginx Configuration
The Nginx container handles static assets directly from public/ and forwards PHP requests over FastCGI to app:9000:
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.php index.html;
client_max_body_size 64M;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 60;
}
# Deny access to hidden dotfiles (.env, .git)
location ~ /\.(?!well-known).* {
deny all;
}
}
10 Step 7: Domain, DNS, Host Reverse Proxy & HTTPS SSL
Point your public domain (e.g., example.com) to the cloud VM's static IP and provision automated Let's Encrypt TLS 1.3 certificates.
10.1 DNS Record Configuration
| Record Type | Host / Name | Value | TTL |
|---|---|---|---|
| A | @ | YOUR_SERVER_PUBLIC_IP | 300 (Auto) |
| A | www | YOUR_SERVER_PUBLIC_IP | 300 (Auto) |
10.2 Host Nginx Reverse Proxy Configuration
Install Nginx on the host and create /etc/nginx/sites-available/example.com.conf:
server {
listen 80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
10.3 Automated SSL Certificate with Certbot
11 Step 8: First Live Deployment (Initial Run)
Execute the initial release sequence to bootstrap database storage and start services:
12 Step 9: Automated CI/CD Deployment with GitHub Actions
Eliminate manual server deployments with a fully automated push-to-deploy workflow:
# .github/workflows/deploy.yml
name: Build, Test & Deploy to Production
on:
push:
branches: [ main ]
jobs:
# 1. Automated Test Quality Gate
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP & Composer
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, pdo_mysql, redis
- run: composer install --no-progress --prefer-dist
- run: php artisan test
# 2. Multi-stage Docker Build & GHCR Publish
build-and-push:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & Push App Image
uses: docker/build-push-action@v6
with:
context: .
file: docker/php/Dockerfile
push: true
tags: ghcr.io/byteionlab/myapp-php:${{ github.sha }}
- name: Build & Push Nginx Image
uses: docker/build-push-action@v6
with:
context: .
file: docker/nginx/Dockerfile
push: true
tags: ghcr.io/byteionlab/myapp-nginx:${{ github.sha }}
# 3. Zero-Touch SSH Remote Deploy
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Execute Remote SSH Deployment
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
./deploy.sh ${{ github.sha }}
Production Deployment Script (/opt/myapp/deploy.sh)
#!/usr/bin/env bash
set -euo pipefail
RELEASE_TAG="${1:?Release SHA required}"
export IMAGE_TAG="$RELEASE_TAG"
echo "=== [Deploying Release: $IMAGE_TAG] ==="
# 1. Pull new immutable image tags
docker compose pull app web worker
# 2. Run safe database migrations
docker compose run --rm --no-deps app php artisan migrate --force
# 3. Update active containers
docker compose up -d --remove-orphans
# 4. Warm caches and restart queue workers
docker compose exec -T app php artisan optimize
docker compose exec -T app php artisan queue:restart
# 5. Live smoke test
echo "Checking Application Health..."
curl -fsS --retry 3 --retry-delay 2 http://127.0.0.1:8080/up
echo "=== [Deployment Succeeded Seamlessly!] ==="
13 Step 10: Production Monitoring, Logging & Alerting
Maintain full observability across three operational layers:
External uptime monitors poll /up every 30 seconds, verifying HTTP 200 responses.
docker stats and Prometheus track CPU, memory saturation, and NVMe disk utilization.
CPU > 90% (5 min), 5xx error rate > 5%, or disk > 85% immediately notify on-call Slack channels.
14 Step 11: Automated Backups & Disaster Recovery
Ensure rapid recovery from catastrophic VM failures with an automated off-site S3 backup cron job:
15 Step 12: Deployment Troubleshooting & Rollback Runbook
When production incidents strike, execute this standardized diagnostic playbook:
| Incident | Probable Cause | Diagnostic Action & Remediation |
|---|---|---|
| HTTP 502 Bad Gateway | Nginx unable to connect to PHP-FPM socket/port 9000 | Run docker compose ps; if app is unhealthy, restart via docker compose restart app. |
| HTTP 500 Server Error | Missing APP_KEY, filesystem permission failure, or PHP fatal error | Inspect logs: docker compose logs --tail=50 app; verify storage permissions and APP_KEY existence. |
| Database Connection Refused | MySQL container down or credential mismatch | Check docker compose logs db; verify DB_HOST=db and synchronize passwords in .env files. |
| Emergency Instant Rollback | Critical bug discovered in latest release | Execute: export IMAGE_TAG=PREVIOUS_SHA && docker compose up -d to roll back immediately. |
Production Deployment Checklist
Verify every security, infrastructure, and operational checkpoint before opening the application to public traffic.
Your cloud application adheres strictly to production engineering standards and is ready for live public traffic.
Interactive Cloud Deployment & Ops Workbench
Zero quizzes! Run automated CI/CD pipelines, troubleshoot live simulated production failures, and inspect container topologies interactively.
GitHub Actions Automated Deploy Simulator
Simulate pushing a commit to main and watch the pipeline test, build, push, and deploy live.
What Did We Learn Across the Course & Capstone?
APP_DEBUG=false and restricting .env file permissions to 600 prevents catastrophic secret leaks.
/up) and CPU/RAM saturation enables proactive remediation before users notice outages.
Congratulations! You Have Completed All 16 Lessons of Cloud & DevOps!
From foundational cloud concepts and datacenters to Docker containerization, networking, CI/CD, Infrastructure as Code, security hardening, observability, auto-scaling, disaster recovery, and an end-to-end production capstone—you are now empowered to design, deploy, and operate resilient production cloud systems.
References & Industry Standards
- Laravel Documentation: Official Deployment Guide & Health Checks
- Docker Documentation: Best Practices for Using Compose in Production
- Ubuntu Server Guide: Security, UFW & TLS Certificate Management
- GitHub Actions Documentation: Continuous Deployment to Cloud VM
- Let's Encrypt / Certbot: Automated Certificate Management Environment (ACME)