Managing AWS Deployments with Docker Compose:
A Practical Guide for DevOps Engineers
As a associate system administrator I worked on Redhat Linux servers, including user management, permissions, services, and performance monitoring Automated routine administrative tasks using Bash scripting and cron jobs, reducing manual effort by ~30% I am aws certified sysops administrator and Google Certified Cloud Engineer. Determined to transition my career into cloud architect /Cloud Support role
Running Docker Compose on AWS for Lean Deployments You don't always need a complex Kubernetes cluster or a massive container orchestration platform to get an app into production. For small-to-medium projects, staging environments, internal tools, or MVP startups, running Docker Compose on AWS is a fast, reliable, and incredibly cost-effective sweet spot.
By pairing Docker Compose with core AWS services like EC2 and Route 53, and tying it all together with GitHub Actions, you can build a streamlined deployment pipeline without the massive cloud bill or operational headache.
Why Stick to Docker Compose on AWS? Docker Compose lets you spin up multi-container applications using a single, readable configuration file. When you deploy this setup on basic AWS infrastructure, you get a few immediate wins:
Zero orchestration overhead: No master nodes or complex networking policies to manage.
Low cost: You only pay for the raw EC2 compute and storage you actually use.
Rapid loops: It speeds up testing, staging, and early-stage deployments dramatically.
Simple CI/CD: You can automate the whole pipeline using straightforward SSH scripts.
The Architecture The most practical setup involves running Docker Compose directly on a single AWS EC2 instance. It’s highly maintainable and easily handles moderate workloads.
How the Pieces Fit Together A typical, production-ready blueprint looks like this:
AWS EC2: Your virtual server acting as the Docker host.
Docker Engine & Compose: To run and manage your application stack (Frontend, Backend API, Database).
Nginx: Functions as a reverse proxy to handle incoming traffic and terminate SSL (via Let's Encrypt).
Amazon Route 53: Manages your domain's DNS records.
GitHub Actions: Handles the build and automated deployment workflow.
[ Developers Push Code ] ──> [ GitHub Actions Build ] │ (via SSH) ▼ ┌──────────────────┐ │ AWS EC2 Host │ │ ┌────────────┐ │ │ │ Nginx │ │ │ └─────┬──────┘ │ │ ▼ │ │ ┌──────────────┐ │ │ │Docker Compose│ │ │ │ ├─ Frontend │ │ │ │ ├─ Backend │ │ │ │ └─ Database │ │ │ └──────────────┘ │ └──────────────────┘ The Deployment Flow Push: You push code updates to your GitHub repository.
Build: GitHub Actions builds your updated Docker images and pushes them to a registry (like Docker Hub or Amazon ECR).
Connect: The pipeline opens a secure SSH connection to your EC2 instance.
Deploy: Docker Compose pulls the fresh images and restarts the containers with minimal downtime:
Bash docker compose pull docker compose up -d The Core Stack Configuration Here is a standard production-ready docker-compose.yml defining a frontend, a backend API, and a persistent PostgreSQL database.
YAML version: '3.9'
services: frontend: image: myorg/frontend:latest
ports: - "80:3000"
backend: image: myorg/backend:latest ports: - "5000:5000"
database: image: postgres:15
environment: POSTGRES_DB: appdb
POSTGRES_USER: admin POSTGRES_PASSWORD: super_secure_password_here volumes: - postgres_data:/var/lib/postgresql/data
volumes: postgres_data:
Setting Up Your AWS Environment :
Recommended EC2 Specs For standard, lightweight workloads, you don't need a massive instance:
Component Target :Spec OS Ubuntu 22.04 LTS Instance Type t3.small or t3.medium Storage 20–50 GB SSD
Network Assign an Elastic IP so your IP doesn't change on reboot Security Group Inbound Rules Make sure your security group restricts access to only what's absolutely necessary:
Port 22 (SSH): For your deployment and administration (restrict to your IP / GitHub CIDRs if possible).
Port 80 (HTTP): Open to the world (redirects to HTTPS).
Port 443 (HTTPS): Open to the world for secure web traffic.
Provisioning the Server Once you SSH into your fresh Ubuntu instance, run the following commands to install Docker and the Compose plugin:
Bash
Update package lists
sudo apt update
Install Docker via the official convenience script
curl -fsSL https://get.docker.com | sh
Install the Compose plugin
sudo apt install docker-compose-plugin -y Verify everything is active and reporting correct versions:
Bash docker --version docker compose version Managing the App To control your stack on the server, navigate to your project directory and use these fundamental commands:
Bash
Start the stack in the background
docker compose up -d
Check running containers
docker compose ps
Tail live application logs
docker compose logs -f
Tear down the stack
docker compose down Production Enhancements
- Adding Nginx as a Reverse Proxy Don't expose your application ports directly to the web. Put Nginx in front to handle SSL termination, caching, and clean routing.
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
} 2. Automating Updates with GitHub Actions To avoid manually logging into your server every time you make a change, use this simple workflow (.github/workflows/deploy.yml) to redeploy automatically on every push to main.
YAML name: Deploy Application
on: push: branches: - main
jobs: deploy: runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.SSH_KEY }}
script: |
cd /opt/app
docker compose pull
docker compose up -d
Best Practices to Keep in Mind Before you go live, check off these foundational security and operational habits:
Enforce HTTPS: Let's Encrypt (certbot) to handle automatic SSL renewals.
Keep Secrets Secret: Never hardcode passwords or API keys in your docker-compose.yml. Use environment files (.env) or AWS Systems Manager Parameter Store.
Automate Backups: Ensure your Docker volumes (especially database storage) are backed up regularly using AWS EBS snapshots.
Tighten Security Groups: Do not open your database ports (e.g., 5432) to the public internet. Keep them internal to the Docker network.
Docker Compose on AWS EC2 is a practical, no-nonsense architecture for running apps without getting bogged down by infrastructure complexity. It keeps your cloud bill predictable and your deployment cycles fast. If your traffic spikes or your architecture demands it down the line, you can easily migrate these exact container configurations to ECS, Fargate, or EKS. Until then, keep it simple.