Building a Simple, Modern, Yet Powerful PaaS Infrastructure for Hosting 30+ ASP.NET Core Demo Applications
A technical deep-dive into self-hosted, container-based deployment
One of the questions I receive most often is surprisingly not about C#, ASP.NET Core, or Clean Architecture.
Instead, it's this:
“How do you host all of your live demo applications?”
Today, I maintain dozens of web application demos—CRM systems, POS applications, ERP modules, HR software, inventory systems, and various reusable templates.
Each application needs to be:
Years ago, the answer was easy. Windows Server. Microsoft IIS. Publish. Done. That changed when I migrated my entire infrastructure to Linux. Ironically, the migration wasn't driven by technology—it was driven by economics.
Running dozens of demo applications on Windows Server works perfectly fine. The problem wasn't capability. It was cost.
A VPS running Windows Server Datacenter with enough CPU and RAM to host many ASP.NET Core applications is significantly more expensive than an equivalent Linux VPS. Once your infrastructure begins growing beyond a few applications, licensing costs become difficult to ignore.
I wanted something that was:
Linux turned out to be the perfect fit. Today, the entire platform runs comfortably on a single VPS with:
8
vCPU
24 GB
RAM
Despite hosting more than thirty applications, the server remains responsive thanks to containerization and careful resource management. The operating system is almost invisible. Docker became the real operating system.
People often imagine Platform as a Service (PaaS) as something incredibly complex. Kubernetes. Service Mesh. Helm Charts. Hundreds of YAML files. For large organizations, those technologies make sense. For an independent software developer? Probably not.
“Deploy a production-ready application with a single Git push.”
That's it. Everything in this infrastructure exists to support that single objective.
Instead of relying on one massive platform, I assembled several focused open-source tools. Each tool does one thing exceptionally well. Together, they form a lightweight but surprisingly capable PaaS.
Self-Hosted Git Repository
about.gitea.com →Every application begins here. Gitea stores all source code repositories for my commercial and internal projects.
I chose Gitea because it is lightweight, fast, self-hosted, open source, and extremely easy to maintain. Running my own Git server also means complete ownership of the development workflow.
Every deployment begins with a Git commit.
Gitea — lightweight self-hosted Git service
Real-world Gitea dashboard — managing multiple repositories for demo applications
Docker & Deployment Management
portainer.io →Portainer is the heart of the platform. Many people think Portainer is simply a Docker dashboard. It is much more than that.
Every application in my infrastructure is defined by a Docker Compose file stored inside its Git repository. Each stack in Portainer continuously monitors its corresponding repository. Whenever new commits arrive, Portainer automatically:
No SSH. No manual publishing. No copying files. No Remote Desktop. Deployment becomes almost effortless. From my perspective, updating production often feels no different from committing code.
Portainer — Docker management and CI/CD automation
Real-world Portainer dashboard — managing 30+ running containers
Reverse Proxy Made Simple
nginxproxymanager.com →If Portainer is the heart, Nginx Proxy Manager is the traffic controller. Every application runs inside Docker. None of them expose ports directly to the internet. Instead, every container communicates through Docker's internal network.
This design provides several advantages. Applications can securely communicate with PostgreSQL, Microsoft SQL Server, CloudBeaver, internal APIs, and other containers without exposing database ports publicly.
Nginx Proxy Manager simply routes incoming HTTPS traffic to the correct container. It also automates one of the most annoying parts of hosting websites: SSL certificates. Let's Encrypt certificates are issued and renewed automatically. No manual renewal. No certificate expiration reminders. No downtime.
Nginx Proxy Manager — reverse proxy with automated SSL
Real-world Nginx Proxy Manager — routing traffic to dozens of containers
Different projects have different requirements. Some customers prefer PostgreSQL. Others require Microsoft SQL Server.
Both database servers run as Docker containers inside the same private network. Applications connect using container names rather than IP addresses. Everything remains isolated from the public internet. Simple. Secure. Reliable.
Browser-Based Database Management
dbeaver.com/cloudbeaver →Managing databases through Remote Desktop or command-line tools quickly becomes inconvenient. CloudBeaver provides a modern browser-based database management interface.
Because it resides inside the same Docker network, it communicates directly with every database container. No SQL Server ports need to be exposed publicly. No PostgreSQL ports either.
Database administration can be performed securely from anywhere using only HTTPS. For me, this is one of those tools that quietly saves hours every month.
CloudBeaver — browser-based database management
Real-world CloudBeaver — managing databases securely via browser
Real-Time Docker Logs & Monitoring
dozzle.dev →One of my favorite discoveries. Dozzle streams Docker logs in real time through an incredibly clean web interface. It also provides quick insight into container activity and overall resource usage.
When one application suddenly consumes more memory than expected, or starts producing unexpected logs, I usually discover it within seconds.
Dozzle intentionally keeps authentication simple. Rather than exposing it publicly, I place it behind Nginx Proxy Manager and enable HTTP Basic Authentication there. This approach keeps the service private while avoiding unnecessary complexity.
Dozzle — real-time Docker log streaming
Real-world Dozzle — monitoring container logs and resource usage
Individually, each tool solves a small problem. Together, they create a surprisingly capable developer platform. The workflow looks like this:
Updating an application often takes less than a minute. The deployment pipeline is almost invisible. Which is exactly how infrastructure should feel.
This platform wasn't designed to impress DevOps engineers. It was designed to remove friction.
As a solo developer, context switching is expensive. Every minute spent manually deploying software is a minute not spent writing software. Automation isn't about replacing people. It's about eliminating repetitive work.
Today I spend far less time thinking about deployment than I did several years ago. That allows me to focus on what actually creates value: building applications.
Every application carries its own runtime, dependencies, and configuration. There are no "works on my machine" surprises anymore.
Almost every service communicates entirely through Docker's internal network. Very few ports are exposed to the public internet. Smaller attack surface, less configuration, greater peace of mind.
Modern deployment pipelines can be remarkably simple. Docker Compose plus Portainer provides more than enough power without introducing unnecessary operational complexity.
Every major component comes from passionate open-source communities. Their work enables independent developers to build infrastructure that would have required an entire operations team just a few years ago.
People often ask what cloud platform I use. The answer surprises them.
There isn't one. Instead, I built a small, focused Platform as a Service tailored specifically to my workflow.
It isn't the biggest. It isn't the most complicated. It certainly isn't the most expensive.
But it quietly hosts more than thirty production demo applications, supports smooth CI/CD deployments, minimizes operational overhead, and lets me concentrate on building software instead of maintaining infrastructure.
“Sometimes, the best engineering solution isn't the most sophisticated one. It's the one that stays out of your way and lets you keep creating.”