How to setup HTTPS endpoint for Ghost on Azure WebApp

Finally I got the blog setup with an HTTPS endpoint on Azure. I thought I would write up on the points that weren't that straight forward.

Get a free SSL certificate

I used Let's encrypt to generate me a free SSL certificate for the blog. It will provide you with a domain-validated certificate, which only vouches for the domain identity (good enough for a blog, if you ask me).

To issue a certificate to a domain, they will challenge you to prove that you control the domain. They generate a string and request you to set it up as a DNS TXT record or as a page in your web server.

Their certificates is valid for three months. So you need to keep renewing it. There is a plugin for Azure Web Apps that handles the process for you, but here I will show the quick & dirty manual way to get it.

Let's encrypt DNS challange

  1. First, you need to get a client. On Arch Linux it was as easy as sudo pacman -S certbot

  2. This will depend on the client you chose, but if you stuck with certbot, that they recommend, then to generate a certificate through the DNS challenge: certbot certonly --manual --preferred-challenges dns -d <your_domain_here>

  3. They will generate you a string that you need to setup as a DNS TXT record on _acme-challange name under the domain your are requesting the certificate for. You can do that in your registrar. I use Google Domain, they have a simple UI to do so:

  4. Google Domains TXT record registration.

  5. Wait a little bit before hitting Enter on the tool, as it takes a while for the DNS record propagation. There are websites that will do a TXT DNS lookup for you. Once you see your record there, you can proceed on the tool.

  6. Azure will require a PFX certificate file format, which is a different format than what certbot generates out of the box. You can convert it to PFX with OpenSSL. Run this on the directory in which the certificate was saved to: openssl pkcs12 -export -out "certificate.pfx" -inkey "privkey.pem" -in "cert.pem" -certfile chain.pem

Set up HTTPS endpoint on Azure Web App

Microsoft has it well documented how to upload your PFX certificate file and configure an HTTPS binding.

HTTP to HTTPS redirection

After that, likely you will want to configure HTTP to HTTPS redirection. This can be done in the web.config with IIS Url Rewrites. Open the web.config (you can do that though Azure portal using the App Service Editor) and add the Redirect to https rule as below:

<configuration>  
  <system.webServer>
    <rewrite>
      <rules>  
        <!-- HTTP to HTTPS redirection -->
        <rule name="Redirect to https">
          <match url="(.*)"/>
            <conditions>
              <add input="{HTTPS}" pattern="Off"/>
            </conditions>
            <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
        </rule>

        <!-- Default rules -->
        <rule name="StaticContent">
          <action type="Rewrite" url="public{REQUEST_URI}"/>
        </rule>
        <rule name="DynamicContent">
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
          </conditions>
          <action type="Rewrite" url="index.js"/>
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>  

Make sure to add the HTTPS redirection rule before the DynamicContent rule. Otherwise IIS will add "index.js" to the end of the URL, likely causing a 404 error.

If you were trying this before and apparently all changes you make to this file have no result, try disabling/clearing your browser cache while testing, as browsers will cache the Redirect response.

Telling Ghost about the new domain

Ghost has a configuration file where it keeps the site's url. You will want to update this to match your new HTTPS endpoint, to have consistency in your blog's links.

If you deployed Ghost using Azure's built in support, then you can simply set the Application Settings variable websiteUrlSSL and websiteUrl to your HTTPS endpoint, like so:

Otherwise, you can just manually change your Ghost configuration file and set the url and urlSSL as described here.