
Deploy .NET Project into VPS using Github Action
What is Github Actions ?
Github Actions is a development tools that allows us to tell Github to do some tasks when some events happen in our repository. What kind of events ? it’s up to us!. For example, when we make a push into main branch, we can tell Github to run some tests, build, and even deploy our project to a server. So, basically, Github gives us a temporary virtual machine and we can tell it what to do and it’s free!
Deploying .NET project into a VPS
Before we start, make sure you have a VPS that runs on linux and you have the SSH access to it. Since it is easier to use docker to run our .NET project, make sure you have docker installed on your VPS. If you don’t have docker installed, you can follow the instructions here. Also make sure you have the docker hub account. If you don’t want to use docker, you can actually use scp to copy the published files to your VPS.
Step 1: Create a new Github Action workflow
First, we need to create a new workflow file in our repository. To do that, create a new file in your repository under the path .github/workflows/deploy.yml
. You can name the file whatever you want, but it must be under the .github/workflows
directory.
Step 2: Define the workflow
In the deploy.yml
file, we need to define the workflow. I will assume you have setup your Dockerfile. Here is an example of a workflow that will deploy a .NET project to a VPS using SSH and Docker:
name: Deploy .NET apps into non-production VPS
on:
push:
branches: [uat]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment: uat
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push Docker image
run: |
docker build -t ${{ secrets.DOCKER_IMAGE_NAME }} .
docker push ${{ secrets.DOCKER_IMAGE_NAME }}
- name: Deploy to VPS
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin <<< "${{ secrets.DOCKER_HUB_TOKEN }}"
docker pull ${{ secrets.DOCKER_IMAGE_NAME }}
docker stop be || true
docker rm be || true
docker run -d \
--name be \
--restart unless-stopped \
-p 8080:8080 \
${{ secrets.DOCKER_IMAGE_NAME }}
Step 3: Add secrets to your repository
In the above workflow, we are using some secrets to store sensitive information like Docker Hub credentials and VPS SSH key. To add secrets to your repository, go to your repository on GitHub, click on Settings
, then click on Secrets
in the left sidebar, and then click on New repository secret
. Notice that in the above workflow, we are uat environtment. Add the following secrets:
DOCKER_HUB_USERNAME
: Your Docker Hub username.DOCKER_HUB_TOKEN
: A Docker Hub access token. You can create one here.DOCKER_IMAGE_NAME
: The name of your Docker image (e.g.,username/repository:tag
).VPS_HOST
: The IP address or hostname of your VPS.VPS_USERNAME
: The username to SSH into your VPS.VPS_SSH_KEY
: The private SSH key to access your VPS. Make sure the corresponding public key is added to the~/.ssh/authorized_keys
file on your VPS
Step 4: Push changes to the repository
Now, whenever you push changes to the uat
branch, the workflow will be triggered, and your .NET project will be built, pushed to Docker Hub, and deployed to your VPS.
What if I don’t want to use Docker?
If you don’t want to use Docker, you can modify any command that uses docker here. Instead of build the docker image, you build & publish the project in the github action machine. Instead of you pull and run the docker image, you copy (using scp) the published project into your vps. Here is an example of how to do that:
name: Deploy .NET apps into non-production VPS
on:
push:
branches: [uat]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment: uat
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '9.0.0' # Change this to your .NET version
- name: Restore, Build & Publish
run: |
dotnet restore
dotnet build --no-restore -c Release
dotnet publish -c Release -o output
- name: Copy files to VPS
uses: appleboy/scp-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.VPS_SSH_KEY }}
source: "./output/*"
target: "~/yourapp"
- name: Deploy to VPS
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
pkill -f 'dotnet yourapp.dll' || true
cd ~/yourapp
nohup dotnet yourapp.dll > app.log 2>&1 &
Bottom line
So now we have learned how to deploy a .NET project to a VPS using Github Actions. The bottom line all we to do is to tell Github to do following tasks:
- Checkout the repository
- Build & publish the project (be it in docker or not)
- Tell Github to connect to our VPS using SSH then run some commands to copy the files or pull the docker image then run it.
Rooms for improvement
There are some rooms for improvement in the above workflow. For examples:
- Add some tests before deploying the project.
- Add notification to Discord/Slack when the deployment is successful or failed.
- Split the workflow into multiple jobs for better readability and maintainability.
- Implement blue-green deployment or canary deployment for zero-downtime deployment.