Free, comprehensive video course from beginner to advanced CI/CD pipelines. Best free Actions resource available. Read →
A complete production pipeline runs automatically on every push to main.
# .github/workflows/deploy-static.yml
name: Deploy Static Site
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci && npm test
deploy:
needs: test # Only if tests pass
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci && npm run build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
aws-region: us-east-1
- name: Sync to S3
run: |
aws s3 sync ./dist s3://BUCKET_NAME --delete --cache-control "public,max-age=31536000,immutable"
aws s3 cp dist/index.html s3://BUCKET_NAME/index.html --cache-control "no-cache"
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation --distribution-id DISTRIBUTION_ID --paths "/*"
# .github/workflows/deploy-docker.yml
name: Build and Deploy Docker
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
permissions: { contents: read, packages: write }
steps:
- uses: actions/checkout@v4
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: GH_ACTOR_VAR
password: GH_TOKEN_VAR
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/OWNER/REPO:GIT_SHA_VAR
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: EC2_HOST_VAR
username: ubuntu
key: EC2_KEY_VAR
script: |
docker pull ghcr.io/OWNER/REPO:GIT_SHA_VAR
docker compose up -d --no-deps api
docker system prune -f
Instead of storing AWS access keys as secrets, use OIDC federation. GitHub Actions gets temporary AWS credentials automatically:
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
aws-region: us-east-1
# No access keys needed — GitHub JWT exchanged for 1-hour AWS credentials
OIDC issues short-lived credentials (1 hour). Nothing to rotate, nothing to leak. Configure once, forget about key management forever. Use OIDC whenever possible.