How To Deploy A Docker Image To A Server Using GitHub Actions
Do you want to learn how to automatically deploy your docker image to your server and, in the same run, update your container using GitHub Actions? In this guide, we will do exactly that! We will first store the image inside GitHub’s Container Registry and then create an Action to deploy it onto the server whenever we push a change!
- Store docker image in GitHub’s Container Registry
- Running the container on your server
- Automate the deployment of your application using GitHub Actions
- Conclusion
You do need a Docker image for this guide. In case you do not have an image yet, check out my last post on how to create one here.
VPS Hosting Course
Learn everything you need to know about servers and hosting your own applications!Store docker image in GitHub’s Container Registry
To store our Docker image, we will use the GitHub Container Registry, which allows us to easily access it from anywhere, especially our server. To store an image in the GHCR, we first need to create a GitHub Personal Access Token (PAT). For more details on the scopes you need and other information, you can check out the GitHub Packages Registry guide. If you want to get started quickly, you can use this link, which includes all the required scopes: https://github.com/
After you click on the link, you need to specify the duration and give the PAT a name, then save the value somewhere secure.
Now, open your terminal and follow these steps from the directory containing the Dockerfile:
- Store your PAT inside an environment variable:
export CR_PAT=<PAT>
- Sign in to the container registry:
echo $CR_PAT | docker login ghcr.io -u <username> --password-stdin
- Build and upload the container image:
docker build . -t ghcr.io/<username>/<image-name>:latest && docker push ghcr.io/<username>/<image-name>:latest
By following these steps, your Docker image will be built and uploaded to the GHCR, and you will be able to access it from your server using the specified image tag. You need to run steps 1 and 2 on your server as well.
Need help or want to share feedback? Join my discord community!
Running the container on your server
The next step is to create a docker-compose.yml
file on our server (inside of /home/<username>/<project>
), which is a template for our Docker container. This way, we can easily move it to another machine or rebuild the containers. Inside the file, we specify the name of the service, the image, and the ports to use:
services:
frontend:
container_name: frontend
image: ghcr.io/programonaut/svelte-counter:latest
ports:
- 80:80
After creating the docker-compose.yml
file, we can build the container by running docker compose up -d
. This command will start the container in detached mode, meaning it runs in the background. To check if your container can be built. If everything works correctly, you can access it under http://<server-ip>
. To learn how to connect it with a domain, check this post here.
If this guide is helpful to you and you like what I do, please support me with a coffee!
Automate the deployment of our application using GitHub Actions
Automating the deployment of our application significantly reduces manual work and speeds up the deployment process. Before we create the secrets and the GitHub Action, we need to set up a new SSH key for it. To do so, log in to your server as the user you want to run the action as and follow these steps:
- Check that user has access to the directory containing the repository and is able to run docker
- Create an SSH key:
ssh-keygen -t rsa -b 4096
- Copy content of the key file:
cat <path/to/private/key>
- Add the public key to the authorized_keys file:
cat <path/to/public/key> >> ~/.ssh/authorized_keys
After creating the SSH key, we need to create the following secrets in the repository by going to Settings > Secrets and Variables > Actions:
SSH_PRIVATE_KEY
: content of the private key fileSSH_USER
: user to access the serverSSH_HOST
: IP of your serverWORK_DIR
: path to the directory containing thedocker-compose.yml
filePAT
: the personal access token to login to the registry
Once the secrets are set up, we can create the following action inside the file .github/workflows/docker-publish.yml
. The action first builds the image and pushes it to the registry inside the publish job, then pulls it onto the server and updates the container in the deploy job.
name: publish
on:
push:
branches: [ "main" ]
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.actor }}/<image-name>:latest
jobs:
publish:
name: publish image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login
run: |
echo ${{ secrets.PAT }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Build and Publish
run: |
docker build . --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
deploy:
needs: publish
name: deploy image
runs-on: ubuntu-latest
steps:
- name: install ssh keys
# check this thread to understand why its needed:
# <https://stackoverflow.com/a/70447517>
run: |
install -m 600 -D /dev/null ~/.ssh/id_rsa
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
- name: connect and pull
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd ${{ secrets.WORK_DIR }} && docker compose pull && docker compose up -d && exit"
- name: cleanup
run: rm -rf ~/.ssh
This job basically logs into the server, pulls the new version of the image, and then rebuilds the containers.
Conclusion
In this guide, you learned how to use GitHub Actions to automatically deploy a docker image to your server! The action first builds the Docker image, pushes it to GitHub’s Container Registry, then pulls the new version onto the server and updates the container!
If you have any questions feel free to leave a comment, join my discord, or send me an email.
[convertkit form=2303042]