---
title: 'You Don''t Need a Dockerfile Anymore'
source: 'https://youtube.com/watch?v=sxnE49qCQt0'
video_id: 'sxnE49qCQt0'
date: 2026-08-08
duration_sec: 554
---

# You Don't Need a Dockerfile Anymore

> Source: [You Don't Need a Dockerfile Anymore](https://youtube.com/watch?v=sxnE49qCQt0)

## Summary

This video demonstrates how to publish .NET applications as Docker containers without a Dockerfile, using the .NET SDK's built-in container publishing feature. It covers the entire workflow from building the image to pushing it to the GitHub Container Registry and running it on a VPS.

### Key Points

- **Introduction to Self-Hosting .NET Apps** [00:01] — The author self-hosts .NET applications by publishing them as Docker containers on a VPS. This video demonstrates how to publish .NET apps as Docker containers and upload them to a container registry.
- **Sample .NET 10 Application** [00:15] — A bare-bones .NET 10 app with a single API endpoint returning the current UTC time, plus OpenAPI and Swagger UI. The app runs on localhost:7256 with a /time endpoint.
- **Traditional Dockerfile Approach** [00:58] — The old way was to create a Dockerfile manually or via right-click → Add → Container Support. The default container build type is Linux, and the generated Dockerfile defines base image, exposes ports, and builds/publishes the project.
- **SDK Container Publishing** [02:03] — Starting from .NET 8, you can build container images directly with the .NET SDK: `dotnet publish -t:PublishContainer`. This works with SLNX solution format and produces a Docker image named after the project.
- **Running the Container** [02:45] — Run with `docker run -p 3000:8080 timeapi` (mapping local port 3000 to container port 8080 for HTTP, 8081 for HTTPS). The app is accessible at localhost:3000/time.
- **Container Registries** [03:42] — Need a place to host images: Docker Hub, Azure, AWS, or GitHub Container Registry (ghcr.io). GitHub offers unlimited storage for public repos and 500MB for private packages.
- **GitHub Container Registry Setup** [04:23] — Create a classic personal access token with `write:packages`, `read:packages`, and `repo` scopes. Log in with `docker login ghcr.io -u username --password-stdin`.
- **Tagging and Pushing** [05:30] — Tag the image with `docker tag time-service ghcr.io/username/timeservice:latest`, then push with `docker push ghcr.io/username/timeservice:latest`. The image appears in GitHub packages and can be pulled on a VPS.
- **Pulling and Running on VPS** [07:52] — On a VPS, `docker pull ghcr.io/username/timeservice:latest` and `docker run -p 3000:3000 ghcr.io/username/timeservice:latest` to run the app.

### Conclusion

The .NET SDK simplifies containerization by eliminating the need for a Dockerfile, and the GitHub Container Registry provides a free, straightforward way to host and deploy your images.

## Transcript

has been self-hosting my .NET applications. The solution I've landed on is publishing them as Docker containers, which I can run on a VPS of my choice. So, in this video, I wanted to show you how you can easily publish
your .NET apps as Docker containers, and how you can get them uploaded to a container registry. So, here's a sample .NET 10 application, and what you'll see is that it's very bare-bones. All I've got is a single API endpoint returning
the current time on the server in the UTC time zone. I'm also exposing an OpenAPI document and also a Swagger UI, but these are just add-ons. If we quickly run this and I send a get request to our API, which is available
on localhost 7256, and our endpoint is time, we're going to So, if you wanted to package this application, you can easily do that by creating a Docker image. How I used to
do this for many years is using a Dockerfile. Now, how you can add this is, for example, writing one yourself, or you can right-click your project and say add and then container support. From this menu, you can choose a couple of
options. Now, the key here is the container build type. You definitely want to run this on Linux as those VPSs are far more affordable, and .NET is cross-platform, so why not? Now, as I was saying about the build type, the
default approach is kind of scaffolding a Dockerfile. And if you go ahead and do that, this is what you're going to get. A Dockerfile that defines the base image, exposes the HTTP and HTTPS ports, and then there's some code to actually
build your project before publishing it here and finally running it using the .NET command. Now, this is a pretty set-it-and-forget-it approach. If you had multiple projects in the solution, you usually have one root project like
an API in this example, and all the project references would be listed here. Now, I'm going to completely delete this, and I want to demo the second approach using the .NET SDK. So, starting from around .NET 8, I believe,
we have the ability to build our .NET applications directly into container images using the .NET SDK. And what that looks like is you go ahead and say .NET publish. You can choose the operating system. Let's say I want to publish this
to Linux, and then I want to say that I want to publish this as a container by saying {dash}t and then publish container. So, if I go ahead and run this, it's going to build my solution. And this also works with the SLNX
solution format. And the end result is a Docker image that has the same name as your .NET project. So, if I now list out any Docker images that I have on my system, you can see the latest one at the top called Time API. So, now my
application is available as a Docker image, and we can run it by saying Docker run. We can specify which ports to expose. Let's say I want to map port to expose. Let's say I want to map port 3000 on the local machine to port 8080,
which is the default Docker port within the container for HTTP, that is. There's also 8081 for HTTPS. And then for the image, I want to say Time API. So, if I go ahead and run this, you can see that my application is now available. What I
actually should have done here is run this in detached mode. So, let me go is up and running, and I should be able to send a request to HTTP localhost 3000, and the endpoint is time, and you can see that we get back a response from
our API. If you got something like Docker Desktop, which I'm using here, the image that it's running, and the port that it's exposed on. I'm going to go ahead and stop it and also get rid of the container. So, you can see that
without having to do anything to my project, I'm able to publish it as a Docker container. The next thing I probably need is somewhere to host my Docker images. What you're looking for is a container registry. There are many
options out there, such as Docker Hub, Azure, and AWS also have container registries. And what I'm going to demo here is the GitHub container registry because it's free to get started. And I do believe, if I'm not mistaken, that
you have unlimited storage for public repositories, and you get about 500 megabytes of storage for your packages for private repositories. Now, you can view any of your packages in the packages tabs on your GitHub profile,
and you can see an example I have here. And the time service is what I actually I'll show you how you can connect this to a repository. Now, before we can get started, we're going to need an access token. So, go ahead and head over to
settings, scroll down to developer settings, and you want to look for personal access tokens. What we need is the classic version. So, I already have create one. So, you're going to say generate new token and then choose
classic. And I just want to comment on these codes that you should select here, the most important one being write packages, read packages, and then the repository scopes. These should be sufficient for our example. Once you
have that, you can use the access token to log in to the GitHub container registry. And how you do that is by saying Docker login, specify the saying Docker login, specify the registry URL, which is ghcr.io,
then you specify your username, and you can provide your password as an argument better approach would be using the standard input output. Now, once you log in to the GitHub container registry, you can go ahead and tag the image that you
slightly different approach where I'll publishing our .NET application. So, we're still publishing as a container Then I have a couple of parameters. I
which is going to translate to the image name, to be time service. And I'm using this to match the name of my repository on GitHub. I'm also specifying the private repository URL. This was one way how I figured out to set the source for
my Docker image, which points to my repository containing the time service code. And I also needed to set publish repository URL to true to have this if you go ahead and run this, we should now see a time service Docker image. So,
I can say Docker inspect and specify time service. And here we see the details for our Docker image. Now, as you can see in the labels here is my image source pointing to my repository, which is needed to connect our package
in the GitHub container registry to our repository. The next thing we want to do repository. The next thing we want to do is to tag our local Docker image. So, we're going to specify it as time service. And then I want to specify the
container registry, which is going to be ghcr.io. And then you want to use your GitHub username, your repository URL, and then you can specify the tag that you want. So, in my case, this is going to be
So, in my case, this is going to be ghcr.io/mnovak/timeservice, course, I messed up because this should be Docker tag, not .NET tag. So, this succeeds. And now, if I go ahead and list out any images that we have
tag that I just wanted to use, and it's pointing to the same image ID as our time service image. So, the next step, once we have tagged this, is to push it going to say Docker push. Then you just specify the full image tag. So, I'm
going to type it out again. So, time service latest, and then this is going to take this image and push it to the respective repository. And then you'll be able to see it inside of GitHub. So, if I open up my time service image, you
can see that it was pushed less than a minute ago. It's also connected to my repository, which you can see here. And now, if I wanted to run this on a VPS, I can say Docker pull, grab my image with this tag that I just used, and run it
inside of a container. Just to give you a glimpse of what this might look like, I'm going to say Docker image rm, and let's get rid of the time service image. It's no longer present locally. And let's also remove the tag that we pushed
to our container registry. Also, I can now say Docker run, and let's expose this on port 3000 locally. And I'm going to specify the image name inside of my container registry. Because we aren't able to find it locally, you can see
that this is now pulled from my container registry repository, and I'm able to run this on my system as any other Docker container. Now, if I want to just quickly run this in detached mode, we can also test it out by sending
mode, we can also test it out by sending a request to localhost 3000/time, can see that our application is working as expected. Now, I know a lot of this is very basic for some of you, but I'm trying to lead into some interesting
videos that I've got coming up that deal with self-hosting your .NET apps on a VPS, so stay tuned for that. And if you're looking to improve as a .NET developer, I've made this roadmap that covers what are all of the fundamental
skills that make up a great .NET developer. If you enjoyed this video, Subscribe to this channel for more videos like this one. Thanks a lot for watching, and until next time, stay awesome.
