<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cool X</title>
    <description>The latest articles on DEV Community by Cool X (@cool_x).</description>
    <link>https://dev.to/cool_x</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3939561%2F3a116d35-0d32-41d8-899e-ae6bc9583bb7.png</url>
      <title>DEV Community: Cool X</title>
      <link>https://dev.to/cool_x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cool_x"/>
    <language>en</language>
    <item>
      <title>AWS_ECR</title>
      <dc:creator>Cool X</dc:creator>
      <pubDate>Tue, 19 May 2026 07:05:03 +0000</pubDate>
      <link>https://dev.to/cool_x/awsecr-4b6p</link>
      <guid>https://dev.to/cool_x/awsecr-4b6p</guid>
      <description>&lt;p&gt;Deploying with AWS ECR + GitHub Actions&lt;br&gt;
A complete CI/CD pipeline: Build → Push to ECR → Deploy to EC2&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is ECR?
ECR (Elastic Container Registry) is AWS's private Docker image registry — think of it as a private Docker Hub that lives inside AWS. Instead of pushing your images to Docker Hub, you push them to ECR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why ECR over Docker Hub?&lt;br&gt;
• Lives inside AWS — pulling from EC2 is fast and free (no egress costs)&lt;br&gt;
• Private by default — no public exposure&lt;br&gt;
• Integrates natively with IAM — no separate login credentials&lt;br&gt;
• Automatically scans images for security vulnerabilities on push&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Big Picture
Here is how all the pieces connect together:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub (your code)&lt;br&gt;
     |&lt;br&gt;
     |  push to main branch&lt;br&gt;
     v&lt;br&gt;
GitHub Actions Runner&lt;br&gt;
     |&lt;br&gt;
     |-- 1. Checkout code&lt;br&gt;
     |-- 2. Configure AWS credentials&lt;br&gt;
     |-- 3. Login to ECR&lt;br&gt;
     |-- 4. Build frontend image&lt;br&gt;
     |-- 5. Push frontend to ECR&lt;br&gt;
     |-- 6. Build backend image&lt;br&gt;
     |-- 7. Push backend to ECR&lt;br&gt;
     |-- 8. SSH into EC2&lt;br&gt;
               |&lt;br&gt;
               |-- pulls frontend from ECR&lt;br&gt;
               |-- pulls backend from ECR&lt;br&gt;
               |-- pulls mariadb from Docker Hub&lt;br&gt;
               |-- pulls adminer from Docker Hub&lt;br&gt;
               |-- runs docker compose up&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ECR Repositories
How many repos do you need?
You only create ECR repos for YOUR custom images. Public official images (MariaDB, Adminer) come directly from Docker Hub — no ECR needed for them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Service Image Source    ECR Repo Needed?&lt;br&gt;
Frontend    Your custom code    YES&lt;br&gt;
Backend Your custom code    YES&lt;br&gt;
MariaDB Docker Hub (mariadb:11) NO&lt;br&gt;
Adminer Docker Hub (adminer:latest) NO&lt;/p&gt;

&lt;p&gt;ECR Repository URL Structure&lt;br&gt;
After creating a repo, AWS gives you a URI like this:&lt;/p&gt;

&lt;p&gt;123456789012.dkr.ecr.ap-south-1.amazonaws.com/myapp-frontend&lt;/p&gt;

&lt;p&gt;123456789012     = your AWS account ID&lt;br&gt;
dkr.ecr          = ECR service&lt;br&gt;
ap-south-1       = your region&lt;br&gt;
amazonaws.com    = AWS domain&lt;br&gt;
/myapp-frontend  = your repository name&lt;/p&gt;

&lt;p&gt;How to Create ECR Repos&lt;br&gt;
AWS Console → ECR → Create Repository → do this twice:&lt;/p&gt;

&lt;p&gt;Settings that matter:&lt;br&gt;
• Visibility: Private (always)&lt;br&gt;
• Tag Immutability: Enabled — prevents overwriting existing tags&lt;br&gt;
• Scan on Push: Enabled — auto scans for CVEs on every push&lt;br&gt;
• Everything else: leave as default&lt;/p&gt;

&lt;p&gt;Create two repos named:&lt;br&gt;
myapp-frontend&lt;br&gt;
myapp-backend&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;IAM — Users and Roles
IAM User vs IAM Role
IAM User    IAM Role
What it is  Permanent identity with fixed keys  Temporary identity, auto-assumed
Has permanent keys? Yes No
Who uses it External things (GitHub Actions)    AWS services (EC2 → ECR)
Credentials Access Key + Secret Key Temporary token (auto-rotated)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;IAM User — for GitHub Actions&lt;br&gt;
GitHub Actions runs on a machine outside AWS. It needs real credentials to prove its identity to AWS.&lt;/p&gt;

&lt;p&gt;Steps to create:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; AWS Console → IAM → Users → Create User&lt;/li&gt;
&lt;li&gt; Name it: github-actions-ecr&lt;/li&gt;
&lt;li&gt; Attach policy: AmazonEC2ContainerRegistryFullAccess&lt;/li&gt;
&lt;li&gt; Security Credentials tab → Create Access Key → choose CLI&lt;/li&gt;
&lt;li&gt; IMPORTANT: Copy both keys immediately — secret shown only once&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;IAM Role — for EC2&lt;br&gt;
EC2 lives inside AWS. Attach a role to the instance instead of putting keys on the server (keys on server = security risk).&lt;/p&gt;

&lt;p&gt;Steps to create:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; AWS Console → IAM → Roles → Create Role&lt;/li&gt;
&lt;li&gt; Trusted entity type: AWS Service → EC2&lt;/li&gt;
&lt;li&gt; Attach policy: AmazonEC2ContainerRegistryReadOnly&lt;/li&gt;
&lt;li&gt; Name it: ec2-ecr-readonly&lt;/li&gt;
&lt;li&gt;EC2 → Instances → your instance → Actions → Security → Modify IAM Role → attach it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify it worked by SSHing into EC2 and running:&lt;br&gt;
aws sts get-caller-identity&lt;br&gt;
If it returns your account ID and role name, the role is working.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub Secrets
Go to: GitHub repo → Settings → Secrets and Variables → Actions → New Repository Secret&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Secret Name Value&lt;br&gt;
AWS_ACCESS_KEY_ID   Your IAM user access key&lt;br&gt;
AWS_SECRET_ACCESS_KEY   Your IAM user secret key&lt;br&gt;
AWS_REGION  e.g. ap-south-1&lt;br&gt;
EC2_HOST    Your EC2 public IP address&lt;br&gt;
EC2_SSH_KEY Full contents of your .pem file (including header/footer)&lt;/p&gt;

&lt;p&gt;For EC2_SSH_KEY — open your .pem file, copy everything including the -----BEGIN RSA PRIVATE KEY----- header and -----END RSA PRIVATE KEY----- footer, paste as the secret value.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ECR Authentication Explained
ECR does not use username/password like Docker Hub. It uses temporary tokens that expire every 12 hours. The command to get and apply the token is:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;aws ecr get-login-password --region ap-south-1 \&lt;br&gt;
  | docker login \&lt;br&gt;
    --username AWS \&lt;br&gt;
    --password-stdin \&lt;br&gt;
    123456789012.dkr.ecr.ap-south-1.amazonaws.com&lt;/p&gt;

&lt;p&gt;• aws ecr get-login-password — asks AWS for a temporary password (valid 12 hours)&lt;br&gt;
• | — pipes that password into the next command&lt;br&gt;
• docker login --username AWS — logs Docker into ECR using the temp password&lt;br&gt;
• --username AWS — ECR always uses the literal string AWS as username, not your IAM username&lt;/p&gt;

&lt;p&gt;In GitHub Actions, the aws-actions/amazon-ecr-login@v1 action runs this automatically. You never write it manually in the workflow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The GitHub Actions Workflow
steps.login-ecr.outputs.registry Explained
This is GitHub Actions syntax for referencing the output of a previous step:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;${{ steps.login-ecr.outputs.registry }}&lt;/p&gt;

&lt;p&gt;steps        = look in previous steps&lt;br&gt;
login-ecr    = the id you gave the step (id: login-ecr)&lt;br&gt;
outputs      = this step exposes output values&lt;br&gt;
registry     = the specific output: your ECR base URL&lt;/p&gt;

&lt;p&gt;Resolves to: 123456789012.dkr.ecr.ap-south-1.amazonaws.com&lt;/p&gt;

&lt;p&gt;The amazon-ecr-login action automatically figures out your account ID and region from your credentials and exposes it as the registry output. Use it instead of hardcoding your account ID.&lt;/p&gt;

&lt;p&gt;Complete Workflow File&lt;br&gt;
Save this as .github/workflows/deploy.yml in your repo:&lt;/p&gt;

&lt;p&gt;name: Build, Push to ECR, Deploy to EC2&lt;/p&gt;

&lt;p&gt;on:&lt;br&gt;
  push:&lt;br&gt;
    branches:&lt;br&gt;
      - main&lt;/p&gt;

&lt;p&gt;jobs:&lt;br&gt;
  deploy:&lt;br&gt;
    runs-on: ubuntu-latest&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;steps:
  - name: Checkout Code
    uses: actions/checkout@v3

  - name: Configure AWS Credentials
    uses: aws-actions/configure-aws-credentials@v2
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: ${{ secrets.AWS_REGION }}

  - name: Login to Amazon ECR
    id: login-ecr
    uses: aws-actions/amazon-ecr-login@v1

  - name: Build and Push Frontend
    env:
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
      IMAGE_TAG: ${{ github.sha }}
    run: |
      docker build -t $ECR_REGISTRY/myapp-frontend:$IMAGE_TAG ./frontend
      docker tag $ECR_REGISTRY/myapp-frontend:$IMAGE_TAG $ECR_REGISTRY/myapp-frontend:latest
      docker push $ECR_REGISTRY/myapp-frontend:$IMAGE_TAG
      docker push $ECR_REGISTRY/myapp-frontend:latest

  - name: Build and Push Backend
    env:
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
      IMAGE_TAG: ${{ github.sha }}
    run: |
      docker build -t $ECR_REGISTRY/myapp-backend:$IMAGE_TAG ./backend
      docker tag $ECR_REGISTRY/myapp-backend:$IMAGE_TAG $ECR_REGISTRY/myapp-backend:latest
      docker push $ECR_REGISTRY/myapp-backend:$IMAGE_TAG
      docker push $ECR_REGISTRY/myapp-backend:latest

  - name: Deploy to EC2
    uses: appleboy/ssh-action@v0.1.10
    with:
      host: ${{ secrets.EC2_HOST }}
      username: ubuntu
      key: ${{ secrets.EC2_SSH_KEY }}
      envs: AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION
      script: |
        aws ecr get-login-password --region $AWS_REGION \
          | docker login \
            --username AWS \
            --password-stdin \
            123456789012.dkr.ecr.ap-south-1.amazonaws.com
        cd /home/ubuntu/myapp
        docker compose pull frontend backend
        docker compose up -d --no-build
        docker image prune -f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Docker Compose File
This file lives both in your GitHub repo and on your EC2 instance at /home/ubuntu/myapp/docker-compose.yml&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;services:&lt;br&gt;
  frontend:&lt;br&gt;
    image: 123456789012.dkr.ecr.ap-south-1.amazonaws.com/myapp-frontend:latest&lt;br&gt;
    ports:&lt;br&gt;
      - "3000:3000"&lt;br&gt;
    depends_on:&lt;br&gt;
      - backend&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;backend:&lt;br&gt;
    image: 123456789012.dkr.ecr.ap-south-1.amazonaws.com/myapp-backend:latest&lt;br&gt;
    ports:&lt;br&gt;
      - "8000:8000"&lt;br&gt;
    depends_on:&lt;br&gt;
      - db&lt;br&gt;
    environment:&lt;br&gt;
      DB_HOST: db&lt;br&gt;
      DB_PORT: 3306&lt;br&gt;
      DB_NAME: myapp&lt;br&gt;
      DB_USER: myuser&lt;br&gt;
      DB_PASS: mypassword&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;db:&lt;br&gt;
    image: mariadb:11&lt;br&gt;
    environment:&lt;br&gt;
      MYSQL_ROOT_PASSWORD: rootpassword&lt;br&gt;
      MYSQL_DATABASE: myapp&lt;br&gt;
      MYSQL_USER: myuser&lt;br&gt;
      MYSQL_PASSWORD: mypassword&lt;br&gt;
    volumes:&lt;br&gt;
      - db_data:/var/lib/mysql&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;adminer:&lt;br&gt;
    image: adminer:latest&lt;br&gt;
    ports:&lt;br&gt;
      - "8080:8080"&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;volumes:&lt;br&gt;
  db_data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Things to Change for Your Project&lt;br&gt;
File    What to Change  Change To&lt;br&gt;
docker-compose.yml  ECR URI in image: fields (x2)   Your actual ECR repo URIs from AWS console&lt;br&gt;
deploy.yml  ./frontend in docker build  Actual path to your frontend folder in repo&lt;br&gt;
deploy.yml  ./backend in docker build   Actual path to your backend folder in repo&lt;br&gt;
deploy.yml  ECR URL in docker login script  Your actual ECR registry base URL&lt;br&gt;
deploy.yml  username: ubuntu    ec2-user if using Amazon Linux, ubuntu if Ubuntu&lt;br&gt;
deploy.yml  /home/ubuntu/myapp  Path where docker-compose.yml lives on EC2&lt;br&gt;
deploy.yml  myapp-frontend / myapp-backend  Your actual ECR repo names if different&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EC2 Instance Setup&lt;br&gt;
SSH into your EC2 and make sure these are installed:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Check Docker
&lt;/h1&gt;

&lt;p&gt;docker --version&lt;/p&gt;

&lt;h1&gt;
  
  
  Check Docker Compose
&lt;/h1&gt;

&lt;p&gt;docker compose version&lt;/p&gt;

&lt;h1&gt;
  
  
  Install AWS CLI if missing
&lt;/h1&gt;

&lt;p&gt;sudo apt update&lt;br&gt;
sudo apt install awscli -y&lt;/p&gt;

&lt;h1&gt;
  
  
  Verify AWS CLI
&lt;/h1&gt;

&lt;p&gt;aws --version&lt;/p&gt;

&lt;h1&gt;
  
  
  Create app directory
&lt;/h1&gt;

&lt;p&gt;mkdir -p /home/ubuntu/myapp&lt;/p&gt;

&lt;p&gt;Copy your docker-compose.yml to EC2 (run this from your local machine):&lt;/p&gt;

&lt;p&gt;scp -i your-key.pem docker-compose.yml ubuntu@your-ec2-ip:/home/ubuntu/myapp/&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Complete Setup Checklist
Do these in order before your first deploy:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;• Create ECR repo: myapp-frontend&lt;br&gt;
• Create ECR repo: myapp-backend&lt;br&gt;
• Create IAM User (github-actions-ecr) with ECR full access&lt;br&gt;
• Generate access keys for IAM user&lt;br&gt;
• Add AWS_ACCESS_KEY_ID to GitHub Secrets&lt;br&gt;
• Add AWS_SECRET_ACCESS_KEY to GitHub Secrets&lt;br&gt;
• Add AWS_REGION to GitHub Secrets&lt;br&gt;
• Add EC2_HOST to GitHub Secrets&lt;br&gt;
• Add EC2_SSH_KEY to GitHub Secrets&lt;br&gt;
• Create IAM Role (ec2-ecr-readonly) with ECR read-only access&lt;br&gt;
• Attach IAM Role to EC2 instance&lt;br&gt;
• Install AWS CLI on EC2&lt;br&gt;
• Create /home/ubuntu/myapp directory on EC2&lt;br&gt;
• Copy docker-compose.yml to EC2&lt;br&gt;
• Create .github/workflows/deploy.yml in your repo&lt;br&gt;
• Push to main branch and watch GitHub Actions tab&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cicd</category>
      <category>docker</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>DEVOPS_ECR</title>
      <dc:creator>Cool X</dc:creator>
      <pubDate>Tue, 19 May 2026 07:03:38 +0000</pubDate>
      <link>https://dev.to/cool_x/devopsecr-107i</link>
      <guid>https://dev.to/cool_x/devopsecr-107i</guid>
      <description>&lt;p&gt;Deploying with AWS ECR + GitHub Actions&lt;br&gt;
A complete CI/CD pipeline: Build → Push to ECR → Deploy to EC2&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is ECR?
ECR (Elastic Container Registry) is AWS's private Docker image registry — think of it as a private Docker Hub that lives inside AWS. Instead of pushing your images to Docker Hub, you push them to ECR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why ECR over Docker Hub?&lt;br&gt;
• Lives inside AWS — pulling from EC2 is fast and free (no egress costs)&lt;br&gt;
• Private by default — no public exposure&lt;br&gt;
• Integrates natively with IAM — no separate login credentials&lt;br&gt;
• Automatically scans images for security vulnerabilities on push&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Big Picture
Here is how all the pieces connect together:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub (your code)&lt;br&gt;
     |&lt;br&gt;
     |  push to main branch&lt;br&gt;
     v&lt;br&gt;
GitHub Actions Runner&lt;br&gt;
     |&lt;br&gt;
     |-- 1. Checkout code&lt;br&gt;
     |-- 2. Configure AWS credentials&lt;br&gt;
     |-- 3. Login to ECR&lt;br&gt;
     |-- 4. Build frontend image&lt;br&gt;
     |-- 5. Push frontend to ECR&lt;br&gt;
     |-- 6. Build backend image&lt;br&gt;
     |-- 7. Push backend to ECR&lt;br&gt;
     |-- 8. SSH into EC2&lt;br&gt;
               |&lt;br&gt;
               |-- pulls frontend from ECR&lt;br&gt;
               |-- pulls backend from ECR&lt;br&gt;
               |-- pulls mariadb from Docker Hub&lt;br&gt;
               |-- pulls adminer from Docker Hub&lt;br&gt;
               |-- runs docker compose up&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ECR Repositories
How many repos do you need?
You only create ECR repos for YOUR custom images. Public official images (MariaDB, Adminer) come directly from Docker Hub — no ECR needed for them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Service Image Source    ECR Repo Needed?&lt;br&gt;
Frontend    Your custom code    YES&lt;br&gt;
Backend Your custom code    YES&lt;br&gt;
MariaDB Docker Hub (mariadb:11) NO&lt;br&gt;
Adminer Docker Hub (adminer:latest) NO&lt;/p&gt;

&lt;p&gt;ECR Repository URL Structure&lt;br&gt;
After creating a repo, AWS gives you a URI like this:&lt;/p&gt;

&lt;p&gt;123456789012.dkr.ecr.ap-south-1.amazonaws.com/myapp-frontend&lt;/p&gt;

&lt;p&gt;123456789012     = your AWS account ID&lt;br&gt;
dkr.ecr          = ECR service&lt;br&gt;
ap-south-1       = your region&lt;br&gt;
amazonaws.com    = AWS domain&lt;br&gt;
/myapp-frontend  = your repository name&lt;/p&gt;

&lt;p&gt;How to Create ECR Repos&lt;br&gt;
AWS Console → ECR → Create Repository → do this twice:&lt;/p&gt;

&lt;p&gt;Settings that matter:&lt;br&gt;
• Visibility: Private (always)&lt;br&gt;
• Tag Immutability: Enabled — prevents overwriting existing tags&lt;br&gt;
• Scan on Push: Enabled — auto scans for CVEs on every push&lt;br&gt;
• Everything else: leave as default&lt;/p&gt;

&lt;p&gt;Create two repos named:&lt;br&gt;
myapp-frontend&lt;br&gt;
myapp-backend&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;IAM — Users and Roles
IAM User vs IAM Role
IAM User    IAM Role
What it is  Permanent identity with fixed keys  Temporary identity, auto-assumed
Has permanent keys? Yes No
Who uses it External things (GitHub Actions)    AWS services (EC2 → ECR)
Credentials Access Key + Secret Key Temporary token (auto-rotated)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;IAM User — for GitHub Actions&lt;br&gt;
GitHub Actions runs on a machine outside AWS. It needs real credentials to prove its identity to AWS.&lt;/p&gt;

&lt;p&gt;Steps to create:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; AWS Console → IAM → Users → Create User&lt;/li&gt;
&lt;li&gt; Name it: github-actions-ecr&lt;/li&gt;
&lt;li&gt; Attach policy: AmazonEC2ContainerRegistryFullAccess&lt;/li&gt;
&lt;li&gt; Security Credentials tab → Create Access Key → choose CLI&lt;/li&gt;
&lt;li&gt; IMPORTANT: Copy both keys immediately — secret shown only once&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;IAM Role — for EC2&lt;br&gt;
EC2 lives inside AWS. Attach a role to the instance instead of putting keys on the server (keys on server = security risk).&lt;/p&gt;

&lt;p&gt;Steps to create:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; AWS Console → IAM → Roles → Create Role&lt;/li&gt;
&lt;li&gt; Trusted entity type: AWS Service → EC2&lt;/li&gt;
&lt;li&gt; Attach policy: AmazonEC2ContainerRegistryReadOnly&lt;/li&gt;
&lt;li&gt; Name it: ec2-ecr-readonly&lt;/li&gt;
&lt;li&gt;EC2 → Instances → your instance → Actions → Security → Modify IAM Role → attach it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify it worked by SSHing into EC2 and running:&lt;br&gt;
aws sts get-caller-identity&lt;br&gt;
If it returns your account ID and role name, the role is working.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub Secrets
Go to: GitHub repo → Settings → Secrets and Variables → Actions → New Repository Secret&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Secret Name Value&lt;br&gt;
AWS_ACCESS_KEY_ID   Your IAM user access key&lt;br&gt;
AWS_SECRET_ACCESS_KEY   Your IAM user secret key&lt;br&gt;
AWS_REGION  e.g. ap-south-1&lt;br&gt;
EC2_HOST    Your EC2 public IP address&lt;br&gt;
EC2_SSH_KEY Full contents of your .pem file (including header/footer)&lt;/p&gt;

&lt;p&gt;For EC2_SSH_KEY — open your .pem file, copy everything including the -----BEGIN RSA PRIVATE KEY----- header and -----END RSA PRIVATE KEY----- footer, paste as the secret value.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ECR Authentication Explained
ECR does not use username/password like Docker Hub. It uses temporary tokens that expire every 12 hours. The command to get and apply the token is:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;aws ecr get-login-password --region ap-south-1 \&lt;br&gt;
  | docker login \&lt;br&gt;
    --username AWS \&lt;br&gt;
    --password-stdin \&lt;br&gt;
    123456789012.dkr.ecr.ap-south-1.amazonaws.com&lt;/p&gt;

&lt;p&gt;• aws ecr get-login-password — asks AWS for a temporary password (valid 12 hours)&lt;br&gt;
• | — pipes that password into the next command&lt;br&gt;
• docker login --username AWS — logs Docker into ECR using the temp password&lt;br&gt;
• --username AWS — ECR always uses the literal string AWS as username, not your IAM username&lt;/p&gt;

&lt;p&gt;In GitHub Actions, the aws-actions/amazon-ecr-login@v1 action runs this automatically. You never write it manually in the workflow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The GitHub Actions Workflow
steps.login-ecr.outputs.registry Explained
This is GitHub Actions syntax for referencing the output of a previous step:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;${{ steps.login-ecr.outputs.registry }}&lt;/p&gt;

&lt;p&gt;steps        = look in previous steps&lt;br&gt;
login-ecr    = the id you gave the step (id: login-ecr)&lt;br&gt;
outputs      = this step exposes output values&lt;br&gt;
registry     = the specific output: your ECR base URL&lt;/p&gt;

&lt;p&gt;Resolves to: 123456789012.dkr.ecr.ap-south-1.amazonaws.com&lt;/p&gt;

&lt;p&gt;The amazon-ecr-login action automatically figures out your account ID and region from your credentials and exposes it as the registry output. Use it instead of hardcoding your account ID.&lt;/p&gt;

&lt;p&gt;Complete Workflow File&lt;br&gt;
Save this as .github/workflows/deploy.yml in your repo:&lt;/p&gt;

&lt;p&gt;name: Build, Push to ECR, Deploy to EC2&lt;/p&gt;

&lt;p&gt;on:&lt;br&gt;
  push:&lt;br&gt;
    branches:&lt;br&gt;
      - main&lt;/p&gt;

&lt;p&gt;jobs:&lt;br&gt;
  deploy:&lt;br&gt;
    runs-on: ubuntu-latest&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;steps:
  - name: Checkout Code
    uses: actions/checkout@v3

  - name: Configure AWS Credentials
    uses: aws-actions/configure-aws-credentials@v2
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: ${{ secrets.AWS_REGION }}

  - name: Login to Amazon ECR
    id: login-ecr
    uses: aws-actions/amazon-ecr-login@v1

  - name: Build and Push Frontend
    env:
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
      IMAGE_TAG: ${{ github.sha }}
    run: |
      docker build -t $ECR_REGISTRY/myapp-frontend:$IMAGE_TAG ./frontend
      docker tag $ECR_REGISTRY/myapp-frontend:$IMAGE_TAG $ECR_REGISTRY/myapp-frontend:latest
      docker push $ECR_REGISTRY/myapp-frontend:$IMAGE_TAG
      docker push $ECR_REGISTRY/myapp-frontend:latest

  - name: Build and Push Backend
    env:
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
      IMAGE_TAG: ${{ github.sha }}
    run: |
      docker build -t $ECR_REGISTRY/myapp-backend:$IMAGE_TAG ./backend
      docker tag $ECR_REGISTRY/myapp-backend:$IMAGE_TAG $ECR_REGISTRY/myapp-backend:latest
      docker push $ECR_REGISTRY/myapp-backend:$IMAGE_TAG
      docker push $ECR_REGISTRY/myapp-backend:latest

  - name: Deploy to EC2
    uses: appleboy/ssh-action@v0.1.10
    with:
      host: ${{ secrets.EC2_HOST }}
      username: ubuntu
      key: ${{ secrets.EC2_SSH_KEY }}
      envs: AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION
      script: |
        aws ecr get-login-password --region $AWS_REGION \
          | docker login \
            --username AWS \
            --password-stdin \
            123456789012.dkr.ecr.ap-south-1.amazonaws.com
        cd /home/ubuntu/myapp
        docker compose pull frontend backend
        docker compose up -d --no-build
        docker image prune -f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Docker Compose File
This file lives both in your GitHub repo and on your EC2 instance at /home/ubuntu/myapp/docker-compose.yml&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;services:&lt;br&gt;
  frontend:&lt;br&gt;
    image: 123456789012.dkr.ecr.ap-south-1.amazonaws.com/myapp-frontend:latest&lt;br&gt;
    ports:&lt;br&gt;
      - "3000:3000"&lt;br&gt;
    depends_on:&lt;br&gt;
      - backend&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;backend:&lt;br&gt;
    image: 123456789012.dkr.ecr.ap-south-1.amazonaws.com/myapp-backend:latest&lt;br&gt;
    ports:&lt;br&gt;
      - "8000:8000"&lt;br&gt;
    depends_on:&lt;br&gt;
      - db&lt;br&gt;
    environment:&lt;br&gt;
      DB_HOST: db&lt;br&gt;
      DB_PORT: 3306&lt;br&gt;
      DB_NAME: myapp&lt;br&gt;
      DB_USER: myuser&lt;br&gt;
      DB_PASS: mypassword&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;db:&lt;br&gt;
    image: mariadb:11&lt;br&gt;
    environment:&lt;br&gt;
      MYSQL_ROOT_PASSWORD: rootpassword&lt;br&gt;
      MYSQL_DATABASE: myapp&lt;br&gt;
      MYSQL_USER: myuser&lt;br&gt;
      MYSQL_PASSWORD: mypassword&lt;br&gt;
    volumes:&lt;br&gt;
      - db_data:/var/lib/mysql&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;adminer:&lt;br&gt;
    image: adminer:latest&lt;br&gt;
    ports:&lt;br&gt;
      - "8080:8080"&lt;br&gt;
    restart: always&lt;/p&gt;

&lt;p&gt;volumes:&lt;br&gt;
  db_data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Things to Change for Your Project&lt;br&gt;
File    What to Change  Change To&lt;br&gt;
docker-compose.yml  ECR URI in image: fields (x2)   Your actual ECR repo URIs from AWS console&lt;br&gt;
deploy.yml  ./frontend in docker build  Actual path to your frontend folder in repo&lt;br&gt;
deploy.yml  ./backend in docker build   Actual path to your backend folder in repo&lt;br&gt;
deploy.yml  ECR URL in docker login script  Your actual ECR registry base URL&lt;br&gt;
deploy.yml  username: ubuntu    ec2-user if using Amazon Linux, ubuntu if Ubuntu&lt;br&gt;
deploy.yml  /home/ubuntu/myapp  Path where docker-compose.yml lives on EC2&lt;br&gt;
deploy.yml  myapp-frontend / myapp-backend  Your actual ECR repo names if different&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EC2 Instance Setup&lt;br&gt;
SSH into your EC2 and make sure these are installed:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Check Docker
&lt;/h1&gt;

&lt;p&gt;docker --version&lt;/p&gt;

&lt;h1&gt;
  
  
  Check Docker Compose
&lt;/h1&gt;

&lt;p&gt;docker compose version&lt;/p&gt;

&lt;h1&gt;
  
  
  Install AWS CLI if missing
&lt;/h1&gt;

&lt;p&gt;sudo apt update&lt;br&gt;
sudo apt install awscli -y&lt;/p&gt;

&lt;h1&gt;
  
  
  Verify AWS CLI
&lt;/h1&gt;

&lt;p&gt;aws --version&lt;/p&gt;

&lt;h1&gt;
  
  
  Create app directory
&lt;/h1&gt;

&lt;p&gt;mkdir -p /home/ubuntu/myapp&lt;/p&gt;

&lt;p&gt;Copy your docker-compose.yml to EC2 (run this from your local machine):&lt;/p&gt;

&lt;p&gt;scp -i your-key.pem docker-compose.yml ubuntu@your-ec2-ip:/home/ubuntu/myapp/&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Complete Setup Checklist
Do these in order before your first deploy:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;• Create ECR repo: myapp-frontend&lt;br&gt;
• Create ECR repo: myapp-backend&lt;br&gt;
• Create IAM User (github-actions-ecr) with ECR full access&lt;br&gt;
• Generate access keys for IAM user&lt;br&gt;
• Add AWS_ACCESS_KEY_ID to GitHub Secrets&lt;br&gt;
• Add AWS_SECRET_ACCESS_KEY to GitHub Secrets&lt;br&gt;
• Add AWS_REGION to GitHub Secrets&lt;br&gt;
• Add EC2_HOST to GitHub Secrets&lt;br&gt;
• Add EC2_SSH_KEY to GitHub Secrets&lt;br&gt;
• Create IAM Role (ec2-ecr-readonly) with ECR read-only access&lt;br&gt;
• Attach IAM Role to EC2 instance&lt;br&gt;
• Install AWS CLI on EC2&lt;br&gt;
• Create /home/ubuntu/myapp directory on EC2&lt;br&gt;
• Copy docker-compose.yml to EC2&lt;br&gt;
• Create .github/workflows/deploy.yml in your repo&lt;br&gt;
• Push to main branch and watch GitHub Actions tab&lt;/p&gt;

</description>
      <category>devopsecr</category>
    </item>
  </channel>
</rss>
