A Step-by-Step Guide to Implementing SSL for Your ASP.NET API.
Creating an ASP.NET API is straightforward, but securing it with HTTPS requires additional steps. In this blog, I’ll walk you through setting up SSL for your ASP.NET API to ensure secure communication.
Table of Content
Containerize your ASP.NET API (with Docker)
Set up Nginx (HTTP)
Create a Certificate with Certbot
Set Up SSL on Nginx (HTTPS)
Automate Certificate Renewal (for Ubuntu)
Summary
Containerize your ASP.NET API
If you have the Docker extension installed in Visual Studio, it will automatically create a container image for your ASP.NET API. You can then upload this image to a registry, such as DockerHub. Here’s how you can use Docker Compose to configure and run your container:
services:
yourapiname:
image: yourusername/yourapi
ports:
- 5556:5000
The Standard Port for the ASP.netAPI is 5000 and is only accessible inside the Container or a Container Network. So, in the configuration, port 5000 is published to port 5556. This means port 5556 should be accessible from the browser. Let's check that by running the command docker-compose up and verifying if the Swagger file is accessible.

If the Swagger file is accessible, we can proceed to set up Nginx.
Set up Nginx (HTTP)
Nginx is a high-performance web server that can also be used as a reverse proxy, load balancer, mail proxy, and HTTP cache. In this setup, we will use Nginx as a reverse proxy to route HTTP requests to our ASP.NET API container.
Our goal is to access the Swagger file over HTTP on the standard port 80. We’ll set up an Nginx server to listen on port 80 and configure it to proxy requests to our API container on internal port 5000. Here’s how you can configure Nginx:
events {
worker_connections 1024;
}
http {
server_tokens off;
charset utf-8;
server {
listen 80;
server_name _;
location /swagger/ {
proxy_pass http://yourapiname:5000/swagger/;
index index.html index.htm;
}
}
}
Save the file and name it nginx.conf.
Now we can update the Docker Compose file:
services:
yourapiname:
image: yourusername/yourapi
nginx:
restart: unless-stopped
image: nginx
ports:
- 80:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
I have removed the port mapping from stoicquotesmailregistrator and added a new container nginx. For the new container, we have exposed port 80 and mapped the config file into the container. When we now run docker-compose up -d, the Swagger file should be available on port 80. Let's check.
The old Page is not accessible anymore:

Port 80 is now working:

Create a Certificate with Certbot
Certbot is a free, open-source tool for automatically using Let’s Encrypt certificates on manually-administrated websites. We need to configure Nginx to serve the challenge files that Certbot will use to verify our domain ownership. Here’s how to set up Certbot with Docker Compose.
Add a challenge location for Certbot in the nginx.conf file:
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
Also, add two volumes to the Nginx container. These are needed so Certbot can communicate with the Nginx server and manage the SSL certificate:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
Then we can add Certbot to the Docker Compose file. Please add your email and your domain in the command:
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: certonly --webroot -w /var/www/certbot --force-renewal --email {mail} -d {domain} --agree-tos
When you run docker-compose up -d, a certificate should be created.
Set Up SSL on Nginx (HTTPS)
o set up the SSL connection, we add a new server block with port 443. We also add the path to the certificates and the location with the link we want to publish.
server {
listen 443 ssl;
# use the certificates
ssl_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{domain}/privkey.pem;
server_name {domain};
location /swagger/ {
proxy_pass http://containerName:5000/swagger/;
index index.html index.htm;
}
}
Replace {domain} with your domain.
This should be it. Run docker-compose up -d and open the site with HTTPS. The certificate should be visible in the browser now.

Automate Certificate Renewal
Let’s Encrypt certificates are only valid for 90 days. To ensure continuous security, we need to automate the renewal process. Add the following command to your crontab to schedule automatic renewals (open with crontab -e):
/usr/bin/docker compose -f /root/projects/reverseProxy-nginx-ssl/docker-compose.yml restart
To change the certificate properly we need to restart the nginx after the certificate was newly created. For that we can add a dependency between nginx and certbot with the depends_on parameter.
nginx:
restart: unless-stopped
depends_on:
certbot:
condition: service_completed_successfully
image: nginx
ports:
- 80:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
Summary
In this guide, we’ve walked through setting up a secure ASP.NET API using Docker, Nginx, and Certbot. We configured Nginx to proxy HTTP and HTTPS requests to our API container and set up automatic certificate renewal. Here are the final configurations for Nginx and Docker Compose:
Nginx Configuration
events {
worker_connections 1024;
}
http {
server_tokens off;
charset utf-8;
access_log /var/log/nginx/access.log;
server {
listen 80;
server_name _;
location /swagger/ {
proxy_pass http://containerName:5000/swagger/;
index index.html index.htm;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
server {
listen 443 ssl;
# use the certificates
ssl_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{domain}/privkey.pem;
server_name {domain};
location /swagger/ {
proxy_pass http://containerName:5000/swagger/;
index index.html index.htm;
}
}
}
Docker Compose Configuration
services:
yourapiname:
image: yourusername/yourapi
nginx:
restart: unless-stopped
depends_on:
certbot:
condition: service_completed_successfully
image: nginx
ports:
- 80:80
- 443:443
volumes:
- /root/projects/reverseProxy-nginx-ssl/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: certonly --webroot -w /var/www/certbot --force-renewal --email <mail> -d <domain> --agree-tos
This is my first blog, so please give me feedback! :)