CI/CD — GitHub → Docker → AWS Lightsail
This page walks through the real CI/CD pipeline behind this site: code changes are pushed to GitHub, built into Docker images, and deployed to an AWS Lightsail instance using an automated GitHub Actions workflow.
Step 1 — Add a YAML workflow file
Create a workflow under .github/workflows/ in your repository (for example, deploy.yml). This file defines what happens when you push to the main branch.
.github/workflows/deploy.yml
Step 2 — Define when the pipeline runs
The workflow runs on pushes to main, so every commit to the primary branch automatically triggers a deployment.
on:
push:
branches: [main]Step 3 — Define the deploy job and check out the code
The deploy job runs on ubuntu-latest and starts by checking out the repository so the workflow can build the Docker image from the latest code.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3Step 4 — Set up Docker Buildx and log in to Docker Hub
The next steps prepare the build environment using docker/setup-buildx-action and authenticate to Docker Hub using credentials stored as GitHub Secrets.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}Using secrets keeps credentials out of the repository while still allowing the workflow to push images to your Docker Hub account.
Step 5 — Build and push the Docker image
The workflow then builds a Linux/amd64 Docker image for the app and pushes it to Docker Hub under mmfay3/softwarerror:latest.
- name: Build and Push Docker Image (linux/amd64)
run: |
docker buildx build \
--platform linux/amd64 \
-t mmfay3/softwarerror:latest \
--push .Using buildx makes it easy to target the same architecture as your Lightsail instance and push in a single step.
Step 6 — SSH into AWS Lightsail and deploy the container
Finally, the workflow uses appleboy/ssh-action to SSH into the Lightsail instance, pull the latest image, stop/remove the old container, and run the new one with the correct environment variables.
- name: SSH into Lightsail and deploy
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.HOST_SSH_KEY }}
script: |
docker pull mmfay3/softwarerror:latest
docker stop softwarerror || true
docker rm softwarerror || true
docker run -d --restart always --name softwarerror \
-p 3000:3000 \
-e EMAIL_HOST=${{ secrets.EMAIL_HOST }} \
-e EMAIL_PORT=${{ secrets.EMAIL_PORT }} \
-e EMAIL_USER=${{ secrets.EMAIL_USER }} \
-e EMAIL_PASS=${{ secrets.EMAIL_PASS }} \
mmfay3/softwarerror:latestThis keeps deployment repeatable: every push to main results in the Lightsail instance running the latest version of the app with the same port mapping and environment settings.
Step 7 — Health checks & next steps
Right now, verification is manual (hitting the site and confirming it's responding). This could be extended with an automated health check step in the workflow or external monitoring/alerting.
- Add a simple curl-based health check after deployment.
- Hook uptime monitoring to the public URL.
- Extend logging/metrics for deeper visibility.