Skip to content
Go back

Deploying .NET applications to Coolify

Published: at 04:45 PM

Background

I recently wrote about moving away from WordPress and DigitalOcean, but I still want to have the option to deploy my web applications to my own VPS. I’m also interested in moving off DigitalOcean and moving to a European alternative. Enter Hetzner, based in Germany.

Old Setup

For a number of years, I ran a VPS on DigitalOcean using WebMin / VirtualMin. It ran for around ten years without any major issues, but it got to the point where it got stuck on a really old version of Ubuntu and it badly needed to be rebuilt. I then tried out the “free” 1-click Plesk deployment, which was licensed for 3 domains (narrator: until Plesk changed the licensing model), and now here we are with the updated personal website running for free on Cloudflare Pages.

Choosing a Self-Hosted PaaS

While I work in Azure at work, I want to try out some alternatives that aren’t big US tech. I have a few options for running .NET if I simply use Docker containers and deploy them:

I am a bit of a sucker for a UI for this kind of thing, and although I could probably settle with pure GitOps, Coolify has a pretty good UI, so I’ll go with that. It also has a bunch of standard applications you can 1-click deploy, from Postgres to Keycloak to Grafana. That’s pretty cool.

Installing Coolify on a Hetzner VPS

Installing Coolify on a Hetzner VPS is out of scope of this article, but if you’re interested, try following CJ’s video walkthrough on YouTube (although I decided to stick with Traefik and not switch to Caddy).

Watch the video walkthrough on YouTube

Creating a Simple .NET Project

I’m a fan of JetBrains Rider at home, although it’s Visual Studio out of choice at work, so jump over to JetBrains and grab yourself a free license for non-commercial use. I then make sure I’ve got the latest .NET SDKs installed (my last update here on my private laptop was .NET 6, so I installed .NET 8 then .NET 9). Then restart Rider and create a .NET 9 minimal API project (just make sure No Controllers is set) and choose to add Docker support. This article isn’t about creating the .NET project. You can just clone the repo if you want to run it yourself.

I wanted to test out some of my own NuGet packages that have .NET Standard support, since I haven’t done that for a while and chose the quieter UK tax UTR number validator and generator. I created two endpoints (one for each function) and then deleted the standard weather service, added the forwarded headers since I knew this was going behind a proxy. I also added the new Microsoft.Extensions.OpenApi and Scalar as a replacement for the now defunct Swashbuckle Swagger UI in .NET 9.

I then pushed that to my GitHub profile in a new repo. I don’t need to build this using GitHub actions. Coolify is going to do this for me in a buildpack.

Setting Up a New Coolify Project

First step is to add a new project to Coolify. Don’t add the new resource to the default project, because it is easier to delete the project in the end than individual resources from that default project (same applies to Azure Resource Groups).

Add a new project in Coolify

Now add the project details and create it.

Add a new project in Coolify - Details

Adding a Resource

Next step is to add a resource. Coolify can use NixPacks as buildpacks, and it does have a .csproj build option, but I want to deploy the standard Dockerfile build. I plan on doing a follow-up post where I deploy a docker-compose as well.

Add a new resource in Coolify

Now enter the resource details and in this case, we are going to access my public GitHub repository, so we grab the URL:

Get the repository URL from GitHub

And paste it in the right place:

Paste the repository URL in Coolify

Now we enter the details of that repo [1] and click Check Repository [2]:

Check the repository in Coolify

Coolify will now do its thing and set up the resource. Now choose the build method “Dockerfile”, since that’s the path we are taking here, but you can choose a docker-compose.yaml or a Nixpack targetting .csproj files. Note: currently Nixpacks don’t have support for .NET Aspire, but when they do it would be awesome. Go ahead and set the build method and clicking Continue:

Select the build method in Coolify

Then you can test it by deploying:

Deploy the project in Coolify

Unfortunately, it doesn’t work the first time, but everything is logged so we can work it out. No stress:

Deployment failure due to Dockerfile issue

cat: can't open '/artifacts/ioo884kk4csss0w8soww8kgk/Blog-Demo-Api/Dockefile/Dockerfile': No such file or directory

Let’s Fix This!

Coolify expects by default that the Dockerfile is in the root folder of the repo. Microsoft, of course, creates solutions and projects in subfolders by default. So now we need to tweak things slightly.

First, we tweak the paths to the Dockerfile.

Fixing Dockerfile paths

I took a quick scan through the rest of the settings and noticed that Coolify had defaulted the portmap to 3000:3000. That isn’t going to work for this app since those are not exposed. So we tweak the Traefik ports since the Dockerfile has defined them (internally) as 8080 and 8081, and we need them to match.

Checking Dockerfile ports

And the matched ports are listed like so:

Matching ports in Traefik load balancer

Deploying

Now we deploy again and cross our fingers:

Deploying the project in Coolify

Finally, we get a successful deployment:

Successful deployment in Coolify

Let’s Test

For these small minimal APIs, I really like the .http file option to test quickly inside Rider (and VS).

You can also install a generator that generates the file for you given an Open API document. How cool is that! First, install the tool:

dotnet tool install --global httpgenerator

Then run your API locally and run:

httpgenerator http://localhost:5283/openapi/v1.json

It will create all of the .http files for you in the current directory the Terminal is running in.

Now you can just tweak you .http file to target your Coolify deployed API, and success!

Successful .http file request execution

Note, I’m using Cloudflare to proxy my DNS. The settings for that are as follows:

Cloudflare Coolify Setup

I hope this guide helps you to have you own play around with Coolify and .NET!

If you’re interested in a follow up to this using docker-compose for a multi-app deployment then let me know in the comments. If you have feedback or questions then also feel free to drop me a comment.

References


Suggest Changes

Next Post
Moving from WordPress on Digital Ocean VPS to Cloudflare Pages and Astro SSG