In the previous post we saw how to deploy Docker Container(s) on a Virtual Machine using Nginx and Docker Hub, and setup SSL and HTTPS using Certbot. In this post we'll see how we can setup a Github Actions workflow, which will deploy our server every time there's a push on the master/main branch. We'll also see how we can configure the release process, and how we can write different pipelines for different branches.
- Public IP of the server (Make sure it's a reserved/elastic IP address so that we can use it on a permanent basis)
- Private Key (
.pem) file that is used to SSH into the server
Setting up Repository Secrets
Along with Github Actions, Github provides a nice feature called Secrets, in which you can store and encrypt sensitive data on a repository/organization level. We'll utilize this to store our Docker Hub Credentials and the Private Key for server access.
Go to Repository Settings
Look for the Secrets tab
Click on Add Repository Secret
Give your secret a name and a secret value
and click on the
Add Secret button to save it
Similarly add your Docker Hub Access Token that we generated in the previous post as
DOCKER_PASSWORD and the content of the Private Key as
At the end, your repository should have these three secrets:
Create a new yml file for our CI/CD workflow
In Github Actions, we've to create a
.yml file for each workflow we want to have in our repositories. You can create a workflow on your repository page on Github.com directly by going to the
Actions tab, and utilize one of the many preconfigured templates by Github according to our use case.
But here, we'll create a workflow configuration from scratch just to understand every part of it.
Create a new folder
.github in the root directory of your project, and inside it create a
Writing the script
Create a new file called
deploy.yml (You can name it anything you want)
Now, we want our workflow to trigger on every push on the master branch. So add this part on the top of the yml file.
But sometimes, we want to have more control on the deployment trigger. For deployments to be triggered manually, we can configure the workflow to run on every release, which has to be created manually.
Next up, we've to define
jobs that the workflow will run. In this case, we only have one job, i.e.,
Add this in the
Here, we're giving our job a name of Deploy which will run on an Ubuntu Virtual Instance.
Next up, we'll add
steps that our job will perform. Here we've three steps,
checkout step is necessary as it will pull our code on the Ubuntu Instance. Then, we first build our image and push it to Docker Hub, and the
deploy step will SSH into our server and, the latest image from Docker Hub and update our App.
Indentations matter a lot in a yml file. So make sure that the script is correctly indented according to the final code given at the end of the article.
Here, we are using a premade Github Action provide by docker itself, which takes away the hassle of writing the scripts of building and pushing an image. Do note that you can find many such helpful actions on Github Marketplace which you can use in your own workflow.
Also, make sure to replace
<DOCKER_HUB_REPO> with your username and repository name on Docker Hub. Replace
<IMAGE_TAG> with the tag you want to give to the image. Let's suppose this image is the production image, so you can give it a tag of
prod. And, if you're deploying both Backend and Frontend on the same server, you can specify the tag
backend accordingly. Do note that in the previous post we've specified these tags in the
Next up, we'll write the steps to SSH into the server, pull the latest image and update the server.
Here, in the first step, we're converting the
PRIVATE_KEY into a private
.pem file for it to be usable in the
After that, we're SSHing into the server and giving it three commands to run.
To pull the latest image(s)
To update the deployment
and finally, to delete unused old containers
Make sure to replace
<SERVER_IP> with your VM's Public IPv4 IP Address.
Once this final step succeeds, our workflow will be complete, and we'll have our latest code up and running on the server without any hassle.
deploy.yml file should look like this
Once you push the deployment script on the main/master branch of your repo, you can see the Deployment in action in the Actions tab. After the deployment is finished, it should look something like this.
Thank you for reaching at the end of the post. If you liked it, please share it among your network. If you found any errors/discrepenceies, you can contact me any time on my mail or fill the contact form on my Portfolio, and I'll get back to you.