Automatically Deploying C# Backend to FTP with Github Actions

Hello, my name is Cem Levent Avcı. I am a senior Computer Engineering student at Eskişehir Osmangazi University. At the same time, I work on both my personal portfolio projects and freelance projects I take on. I develop applications in both frontend and backend, mainly using technologies such as Laravel, Next.js, and C#. I also strive to automate my projects with CI/CD pipelines. In this article, I will walk you step by step through the process of automatically building a C# backend project using GitHub Actions and deploying it via FTP.
What is GitHub Actions and What Does It Do?
GitHub Actions is a CI/CD (Continuous Integration / Continuous Deployment) tool that runs directly on GitHub. In other words, with this tool, we can automatically test, build, and deploy every change made in our project.
What is CI/CD?
Continuous Integration is the process where code changes are continuously integrated into the main project. Each change goes through automated tests, and errors are detected at an early stage. This helps teams maintain high code quality and minimize conflicts.
Continuous Deployment / Delivery is the process of automatically deploying code that has passed the tests to the production or staging environment. While Continuous Delivery requires manual approval for deployment, Continuous Deployment happens fully automatically. This way, new features or fixes can quickly reach the users.
What Does GitHub Actions Provide Us?
GitHub Actions is a tool that increases automation, reduces errors, and simplifies workflow management in modern software development processes. Here are its main advantages:
Automated Build and Test: Every change made in the Git repository is automatically tested and built thanks to GitHub Actions. This ensures that errors are detected before the project progresses and prevents faulty code from being pushed to production. Automated testing and build processes improve project quality while also saving developers time.
Continuous Integration and Deployment: The CI/CD mechanism enables code to be continuously integrated and deployed without manual intervention. Developers can define separate jobs for environments like development, staging, and production. This way, new features or fixes can be delivered to users quickly and securely.
Workflow Management with Version Control: All workflow steps are stored inside the repository as
.ymlfiles and kept under version control. This allows workflow changes to be tracked just like code changes and collaboratively improved by team members. Workflow management enhances team coordination and standardizes processes.Flexibility and Integration: GitHub Actions works seamlessly with different languages and platforms such as Node.js, C#, Python, and Java. It can also integrate with popular deployment and service tools like Docker, Kubernetes, FTP, AWS, and Azure. Workflows can be further customized with conditions, parallel jobs, and caching mechanisms, making processes more flexible and optimized.
Speed and Efficiency: Since repetitive tasks are automated, developers can use their time more efficiently. Testing, building, and deployment processes become standardized; human errors are minimized, and projects can be delivered to production faster.
Creating a Sample C# Backend Deployment Workflow with GitHub Actions
1. Git Repository File Structure
my-repo/
├─ .github/
│ └─ workflows/
│ └─ deploy.yml # Github Actions workflow file
├─ backend_api/
│ ├─ backend_api.sln # Solution file
│ ├─ backend_api.csproj # Project file
│ ├─ Program.cs
│ ├─ ...
└─ README.md2.deploy.yml file
name: Backend Deploy via FTP # @1
on: # @2
push:
branches:
- main
jobs: # @3
backend-deploy:
runs-on: ubuntu-latest
steps: # @4
- name: Checkout code # @5
uses: actions/checkout@v4
- name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
dotnet-version: "9.0.x"
- name: Restore dependencies
run: dotnet restore ./backend_api/backend_api.sln
- name: Publish backend
run: dotnet publish ./backend_api/backend_api.csproj -c Release -o ./backend/publish
- name: Verify templates are included # optional
run: |
echo "Checking if templates are included in publish output..."
ls -la ./backend/publish/templates/
echo "Template files found:"
find ./backend/publish/templates/ -name "*.html" -type f
- name: Deploy backend via FTP
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
protocol: ftp
port: 21
timeout: 190000
log-level: verbose
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
local-dir: ./backend/publish/
server-dir: /api.yourdomain.com/The
name:parameter is the name that will appear in the GitHub Actions workflow panel. You can name it however you want it to be displayed there.The
on:parameter defines under which conditions the workflow will run. In the currentdeploy.ymlfile, the workflow will be triggered on every push to themainbranch of our repository, and the deployment process will begin.The
jobs:parameter defines the jobs within the workflow. In our current workflow, only one job namedbackend-deployis defined. Theruns-on:parameter specifies the operating system on which this job will run.The
steps:parameter defines the sequential steps that will be executed inside a job. From this point onward, the actions to be performed are listed step by step with different names.In the
name: Checkout codestep, the code from our repository is pulled into the workflow environment.In the
name: Setup .NET 9step, the .NET SDK 9 is installed in the workflow environment. This allows the C# backend project to be built and published using this version.In the
name: Restore dependenciesstep, all NuGet packages in the project are downloaded. The required dependencies are thus prepared for the build and publish processes.In the
name: Publish backendstep, the project is compiled in Release mode, and the files to be published are output into the./backend/publishfolder. This folder will then be sent to the server via FTP.The
name: Verify templates are includedstep is optional. You may not need to include this step in your own workflow. In my case, since my project required HTML templates, I added this verification to ensure they were included before deploying to the server. In short, this step checks whether the relevant files exist in the workflow.In the
name: Deploy backend via FTPstep, the files we just published are uploaded to the server via FTP usingSamKirkland/FTP-Deploy-Action@v4.3.5. For this step to work, you must add FTP credentials as repository secrets under “Secrets and Variables” → “Actions secrets” in your repository settings. These secrets should include:FTP_SERVER(the IP address or domain of the FTP server)FTP_USERNAMEFTP_PASSWORD
By setting
log-level: verbose, you can view the FTP upload process and any errors in detail. Thelocal-dirparameter specifies the path of the files we previously published, indicating where to take the files from. Theserver-dirparameter specifies where the files will be uploaded on the server. For example, you can create a subdomain in the Plesk panel and deploy under it (which is what I did). If you want to deploy directly to the main domain, you can change it to/httpdocs/in Plesk, depending on your needs.
Thank you for reading! I hope the information I shared about automating the deployment process of C# backend projects with GitHub Actions has been helpful to you.
Please feel free to reach out to me for any questions, feedback, or project collaborations. Exchanging ideas on technology, software, and automation, as well as discussing new projects, is always very valuable to me.
You can contact me through the following channels:
Email: cemlevent54@gmail.com
LinkedIn: linkedin.com/in/leventavci54
GitHub: github.com/cemlevent54
Personal Website: https://cemleventavci.com.tr – You can visit to see my portfolio and the projects I’ve worked on.

