<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Timon's Blog]]></title><description><![CDATA[Timon's Blog]]></description><link>https://blog.timongartung.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 16:32:40 GMT</lastBuildDate><atom:link href="https://blog.timongartung.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Step-by-Step Guide to Implementing SSL for Your ASP.NET API.]]></title><description><![CDATA[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 ...]]></description><link>https://blog.timongartung.com/a-step-by-step-guide-to-implementing-ssl-for-your-aspnet-api</link><guid isPermaLink="true">https://blog.timongartung.com/a-step-by-step-guide-to-implementing-ssl-for-your-aspnet-api</guid><category><![CDATA[Docker]]></category><category><![CDATA[SSL]]></category><category><![CDATA[nginx]]></category><category><![CDATA[ASP.NET]]></category><category><![CDATA[beginner]]></category><category><![CDATA[Ubuntu]]></category><dc:creator><![CDATA[Timon Gartung]]></dc:creator><pubDate>Tue, 02 Jul 2024 04:27:38 GMT</pubDate><content:encoded><![CDATA[<p>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 <a target="_blank" href="http://ASP.NET">ASP.NET</a> API to ensure secure communication.</p>
<h2 id="heading-table-of-content">Table of Content</h2>
<ul>
<li><p>Containerize your ASP.NET API (with Docker)</p>
</li>
<li><p>Set up Nginx (HTTP)</p>
</li>
<li><p>Create a Certificate with Certbot</p>
</li>
<li><p>Set Up SSL on Nginx (HTTPS)</p>
</li>
<li><p>Automate Certificate Renewal (for Ubuntu)</p>
</li>
<li><p>Summary</p>
</li>
</ul>
<h2 id="heading-containerize-your-aspnet-api">Containerize your ASP.NET API</h2>
<p>If you have the Docker extension installed in Visual Studio, it will automatically create a container image for your <a target="_blank" href="http://ASP.NET">ASP.NET</a> 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:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">yourapiname:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">yourusername/yourapi</span>
    <span class="hljs-attr">ports:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-number">5556</span><span class="hljs-string">:5000</span>
</code></pre>
<p>The Standard Port for the <a target="_blank" href="http://ASP.net">ASP.net</a><a target="_blank" href="http://asp.net/">API</a> 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 <code>docker-compose up</code> and verifying if the Swagger file is accessible.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732963259934/627262eb-e47f-4fad-9dd7-3c6cfe43e00f.jpeg" alt class="image--center mx-auto" /></p>
<p>If the Swagger file is accessible, we can proceed to set up Nginx.</p>
<h2 id="heading-set-up-nginx-http">Set up Nginx (HTTP)</h2>
<p>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 <a target="_blank" href="http://ASP.NET">ASP.NET</a> API container.</p>
<p>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:</p>
<pre><code class="lang-nginx"><span class="hljs-section">events</span> {
    <span class="hljs-attribute">worker_connections</span> <span class="hljs-number">1024</span>;
}

<span class="hljs-section">http</span> {
    <span class="hljs-attribute">server_tokens</span> <span class="hljs-literal">off</span>;
    <span class="hljs-attribute">charset</span> utf-<span class="hljs-number">8</span>;
    <span class="hljs-section">server</span> {
        <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;

        <span class="hljs-attribute">server_name</span> _;

        <span class="hljs-attribute">location</span> /swagger/ {
            <span class="hljs-attribute">proxy_pass</span> http://yourapiname:5000/swagger/;
            <span class="hljs-attribute">index</span>  index.html index.htm;
        } 
    }
}
</code></pre>
<p>Save the file and name it <code>nginx.conf</code>.</p>
<p>Now we can update the Docker Compose file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">yourapiname:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">yourusername/yourapi</span>

  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">ports:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-number">80</span><span class="hljs-string">:80</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx/nginx.conf:/etc/nginx/nginx.conf</span>
</code></pre>
<p>I have removed the port mapping from <code>stoicquotesmailregistrator</code> and added a new container <code>nginx</code>. For the new container, we have exposed port 80 and mapped the config file into the container. When we now run <code>docker-compose up -d</code>, the Swagger file should be available on port 80. Let's check.</p>
<p>The old Page is not accessible anymore:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732963617625/4b1cfee1-296c-46c7-86ad-a88856063894.jpeg" alt class="image--center mx-auto" /></p>
<p>Port 80 is now working:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732963771214/02683af9-34cd-40a5-810a-324107bfc820.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-create-a-certificate-with-certbot">Create a Certificate with Certbot</h2>
<p>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.</p>
<p>Add a challenge location for Certbot in the <code>nginx.conf</code> file:</p>
<pre><code class="lang-nginx"><span class="hljs-attribute">location</span> <span class="hljs-regexp">~ /.well-known/acme-challenge/</span> {
    <span class="hljs-attribute">root</span> /var/www/certbot;
}
</code></pre>
<p>Also, add two volumes to the Nginx container. These are needed so Certbot can communicate with the Nginx server and manage the SSL certificate:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/conf:/etc/letsencrypt</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/www:/var/www/certbot</span>
</code></pre>
<p>Then we can add Certbot to the Docker Compose file. Please add your email and your domain in the command:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">certbot:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">certbot/certbot</span>
    <span class="hljs-attr">volumes:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/conf:/etc/letsencrypt</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/www:/var/www/certbot</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">certonly</span> <span class="hljs-string">--webroot</span> <span class="hljs-string">-w</span> <span class="hljs-string">/var/www/certbot</span> <span class="hljs-string">--force-renewal</span> <span class="hljs-string">--email</span> {<span class="hljs-string">mail</span>} <span class="hljs-string">-d</span> {<span class="hljs-string">domain</span>} <span class="hljs-string">--agree-tos</span>
</code></pre>
<p>When you run <code>docker-compose up -d</code>, a certificate should be created.</p>
<h2 id="heading-set-up-ssl-on-nginx-https">Set Up SSL on Nginx (HTTPS)</h2>
<p>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.</p>
<pre><code class="lang-nginx">    <span class="hljs-section">server</span> {
        <span class="hljs-attribute">listen</span> <span class="hljs-number">443</span> ssl;
        <span class="hljs-comment"># use the certificates</span>
        <span class="hljs-attribute">ssl_certificate</span> /etc/letsencrypt/live/{domain}/fullchain.pem;
        <span class="hljs-attribute">ssl_certificate_key</span> /etc/letsencrypt/live/{domain}/privkey.pem;
        <span class="hljs-section">server_name</span> {domain};

        <span class="hljs-attribute">location</span> /swagger/ {
            <span class="hljs-attribute">proxy_pass</span> http://containerName:5000/swagger/;
            <span class="hljs-attribute">index</span>  index.html index.htm;
        }
    }
</code></pre>
<p><em>Replace</em> <code>{domain}</code> <em>with your domain.</em></p>
<p>This should be it. Run <code>docker-compose up -d</code> and open the site with HTTPS. The certificate should be visible in the browser now.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732963858742/5e09c7cf-9932-48fb-90c4-930dd6846f54.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-automate-certificate-renewal">Automate Certificate Renewal</h2>
<p>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 <code>crontab -e</code>):</p>
<pre><code class="lang-bash">/usr/bin/docker compose -f /root/projects/reverseProxy-nginx-ssl/docker-compose.yml restart
</code></pre>
<p>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 <code>depends_on</code> parameter.</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
    <span class="hljs-attr">depends_on:</span> 
      <span class="hljs-attr">certbot:</span>
        <span class="hljs-attr">condition:</span> <span class="hljs-string">service_completed_successfully</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">ports:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-number">80</span><span class="hljs-string">:80</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx/nginx.conf:/etc/nginx/nginx.conf</span>
</code></pre>
<h1 id="heading-summary">Summary</h1>
<p>In this guide, we’ve walked through setting up a secure <a target="_blank" href="http://ASP.NET">ASP.NET</a> 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:</p>
<h3 id="heading-nginx-configuration">Nginx Configuration</h3>
<pre><code class="lang-nginx"><span class="hljs-section">events</span> {
    <span class="hljs-attribute">worker_connections</span> <span class="hljs-number">1024</span>;
}

<span class="hljs-section">http</span> {
    <span class="hljs-attribute">server_tokens</span> <span class="hljs-literal">off</span>;
    <span class="hljs-attribute">charset</span> utf-<span class="hljs-number">8</span>;

      <span class="hljs-attribute">access_log</span>  /var/log/nginx/access.log;

    <span class="hljs-section">server</span> {
        <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;

        <span class="hljs-attribute">server_name</span> _;

        <span class="hljs-attribute">location</span> /swagger/ {
            <span class="hljs-attribute">proxy_pass</span> http://containerName:5000/swagger/;
            <span class="hljs-attribute">index</span>  index.html index.htm;
        }

        <span class="hljs-attribute">location</span> / {
            <span class="hljs-attribute">root</span>   /usr/share/nginx/html;
            <span class="hljs-attribute">index</span>  index.html index.htm;
        }

        <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ /.well-known/acme-challenge/</span> {
            <span class="hljs-attribute">root</span> /var/www/certbot;
        } 
    }

    <span class="hljs-section">server</span> {
        <span class="hljs-attribute">listen</span> <span class="hljs-number">443</span> ssl;
        <span class="hljs-comment"># use the certificates</span>
        <span class="hljs-attribute">ssl_certificate</span> /etc/letsencrypt/live/{domain}/fullchain.pem;
        <span class="hljs-attribute">ssl_certificate_key</span> /etc/letsencrypt/live/{domain}/privkey.pem;
        <span class="hljs-section">server_name</span> {domain};

        <span class="hljs-attribute">location</span> /swagger/ {
            <span class="hljs-attribute">proxy_pass</span> http://containerName:5000/swagger/;
            <span class="hljs-attribute">index</span>  index.html index.htm;
        }
    }
}
</code></pre>
<h3 id="heading-docker-compose-configuration">Docker Compose Configuration</h3>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">yourapiname:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">yourusername/yourapi</span>

  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
    <span class="hljs-attr">depends_on:</span> 
      <span class="hljs-attr">certbot:</span>
        <span class="hljs-attr">condition:</span> <span class="hljs-string">service_completed_successfully</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">ports:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-number">80</span><span class="hljs-string">:80</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">443</span><span class="hljs-string">:443</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">/root/projects/reverseProxy-nginx-ssl/nginx/nginx.conf:/etc/nginx/nginx.conf</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/conf:/etc/letsencrypt</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/www:/var/www/certbot</span>

  <span class="hljs-attr">certbot:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">certbot/certbot</span>
    <span class="hljs-attr">volumes:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/conf:/etc/letsencrypt</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./certbot/www:/var/www/certbot</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">certonly</span> <span class="hljs-string">--webroot</span> <span class="hljs-string">-w</span> <span class="hljs-string">/var/www/certbot</span> <span class="hljs-string">--force-renewal</span> <span class="hljs-string">--email</span> <span class="hljs-string">&lt;mail&gt;</span> <span class="hljs-string">-d</span> <span class="hljs-string">&lt;domain&gt;</span> <span class="hljs-string">--agree-tos</span>
</code></pre>
<p>This is my first blog, so please give me feedback! :)</p>
]]></content:encoded></item></channel></rss>