Health Checks in nginx
Health Checks in nginx
May 4, 2025

As some of you know, I create YouTube videos called Coding Shorts. Ironically, they are not YouTube shorts (they predate them), but are 10-ish minute videos on topics I like. I’ve been doing a number of these on Aspire, but I’ve been stuck on my “Aspire Deployment” video for a while now.

One of the things I missed was that we need health checks on most of different elements of the app. Most examples out there use ASP.NET Core + Blazor. As I’m not that keen on Blazor, I’ve been doing them with JavaScript frontends. But I didn’t want to deploy them as part of the API or worker processes, but instead just deploy them as separate containers. For this I use nginx.

Essentially, I just create a container to host the frontend like so:

FROM nginx:alpine

# Copy the built site to the root of the webserver
COPY ./_site /var/nginx/www/

# Add a config as necessary
ADD ./default.conf /etc/nginx/conf.d/default.conf

# expose the default port
EXPOSE 80/tcp

# Run the server
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]

This works great and is tiny in size. In fact, I use it for my blog as well (as Static Websites didn’t like the sheer size of my site as I have 20+ years of blog posts).

One small problem, how to have a healthcheck so that the Azure Container App or Kubernetes knows that it is up? After some Googling, I found a solution, but it involves the nginx config file. So, let’s start with a simple configuration file:

# default.conf
server {
    listen       80;
    server_name  localhost;
    gzip on;
    access_log  /var/log/nginx/host.access.log  main;
    root /var/nginx/www/;

    index index.html index.htm; 

    error_page  404 /404/;
}

This configuration just specifies:

  • What directory the content is contained in (see the copy in the docker file)
  • Turn on gzip compression
  • Specify that any url that does not contain an extension, will attempt to use index.{html,htm} for the default name.
  • Specifies the error page to go to a static page at /404/.

But here is where we can add our own healthcheck:

    location = /health {
            access_log off;
            add_header 'Content-Type' 'application/json';
            return 200 '{"status":"UP"}';
    }

Adding this just reutrns a simple status when /health is called. That’s it. Obviously, you can modify what is returned, but as long as the server is up, it will return on /health.

What are you thoughts? Can it be improved? Let me know in the comments!