What I Wanted to Do
I wanted to automatically build and push a Docker image to Docker Hub every time I pushed code to main. Manually running builds every time got old fast, so I set up GitHub Actions to handle it.
Register Docker Hub Credentials as Secrets
First, create an access token from Docker Hub: Account Settings → Security → New Access Token.
In your GitHub repository, go to Settings → Secrets and variables → Actions and add:
DOCKERHUB_USERNAME: your Docker Hub usernameDOCKERHUB_TOKEN: the access token you just created
Always use an Access Token, not your password.
Create the Workflow File
mkdir -p .github/workflows
Create .github/workflows/docker-push.yml:
name: Docker Build and Push
on:
push:
branches:
- main
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/my-app:latest
Tag Images with the Git SHA
Using only latest makes it hard to trace which commit produced a given image.
Add the commit SHA as an extra tag so every image is traceable:
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/my-app:latest
${{ secrets.DOCKERHUB_USERNAME }}/my-app:${{ github.sha }}
Build-Only Check on Pull Requests
Before merging into main, it’s handy to verify the build passes without actually pushing the image.
Set push: false for pull request events:
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to Docker Hub
if: github.event_name == 'push'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name == 'push' }}
tags: ${{ secrets.DOCKERHUB_USERNAME }}/my-app:latest
Things That Tripped Me Up
- Using your Docker Hub password instead of an Access Token causes an authentication error
docker/build-push-actionexpects the Dockerfile in the repo root. Usecontextorfileto point elsewhere- Hardcoding your username in
tagswill break if you update Secrets. Always read it from Secrets - GitHub Actions free tier: unlimited minutes for public repos, 2,000 minutes/month for private repos
Related Articles
- GitHub Actions: How to Set Up Basic Auto-Deploy
- Managing Secrets in GitHub Actions
- Dockerfile Basics: FROM, RUN, COPY, CMD, EXPOSE
- Set Up Docker on a VPS (Ubuntu)
- Docker Basic Commands Cheatsheet (run/stop/rm/ps)
Recommended Services
- Fiverr - Find freelance developers and tech experts