Chat with LLM: Obtain a Free SSL Certificate

Introduction

The production server for a project I am working on is an Azure VM that's only accessible via an IP address, which couldn't establish HTTPS connections. This is a situation I found unsatisfactory. To enable HTTPS, we first need to register a domain name, then configure DNS resolution, and finally apply for an SSL certificate. The key to achieving this for free lies in obtaining a domain name at no cost, since Cloudflare offers free DNS resolution services and Let's Encrypt provides free SSL certificates. However, acquiring a free domain name is challenging, and Cloudflare might not recognize such free domains. Consequently, I kept postponing this task.

Recently, while conversing with an LLM again, I discovered that Azure allows us to claim a free domain name ([your-chosen-prefix].[vm-region].cloudapp.azure.com) for a VM's public IP address, and it also provides free DNS resolution services. This significantly simplified my task, as Azure had handled the most difficult part. I only needed to apply for the SSL certificate.

Thus, this blog post was born: how to apply for a free SSL certificate from Let's Encrypt. Note that the vast majority of this post's content was generated by an LLM. I successfully obtained the SSL certificate by following these instructions, so I decided to document them.

Steps

1️⃣ Prepare Directories and Configuration

Create two directories on the host machine for storing verification files and certificates.

1
2
mkdir -p /mydata/certbot/www /mydata/certbot/ssl
chmod -R 755 /mydata/certbot
  • www/: Used to store Let's Encrypt verification files, needs to be mounted into the Nginx container.
  • ssl/: Used to store the generated SSL certificate files.

2️⃣ Configure Nginx for Verification

You need to modify your Nginx container's configuration or startup parameters to ensure it can serve the verification files under the .well-known/acme-challenge path. Add the following server block to your Nginx configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name your-domain.com; # e.g., example.com

# This path is used by Let's Encrypt for domain ownership verification
location /.well-known/acme-challenge/ {
# This path must correspond to the Webroot path mounted when running the Certbot container
root /var/www/certbot;
allow all; # Allow access from Let's Encrypt's servers
}

# Other configurations...
# location / { ... }
}

3️⃣ Modify Nginx Startup Command: When starting the Nginx container, you must mount the host directory /mydata/certbot/www to the container path /var/www/certbot (or the path you specified in your configuration).

1
2
3
4
5
6
docker run -d \
--name your-nginx-container \
-p 80:80 \
-v /mydata/certbot/www:/var/www/certbot \
-v /path/to/your/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:latest

4️⃣ Run Certbot Container to Request Certificate

Use the following command to run a temporary Certbot container to obtain the certificate. Remember to replace your-domain.com with your actual domain.

1
2
3
4
5
6
7
8
9
docker run --rm \
-v /mydata/certbot/ssl:/etc/letsencrypt \
-v /mydata/certbot/www:/var/www/certbot \
certbot/certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
-d your-domain.com \
--agree-tos \
--non-interactive

If successful, you will see a message like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for your-domain.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your-domain.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/your-domain.com/privkey.pem
This certificate expires on 2026-02-20.
These files will be updated when the certificate renews.
NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Your certificate and private key files will be saved in the host directory /mydata/certbot/ssl/live/your-domain.com/.

5️⃣ Configure Nginx to Use the SSL Certificate

Now, add HTTPS configuration for your Nginx service. You need to create a server block listening on port 443 and reference the newly obtained certificates.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 443 ssl;
server_name your-domain.com;

# SSL certificate configuration
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3; # Enable secure protocol versions

# Your other website configurations...
# location / { ... }
}

# Redirect HTTP traffic to HTTPS
server {
listen 80;
server_name your-domain.com;
return 301 https://$host$request_uri;
}

6️⃣ Modify Nginx Startup Command: When starting the HTTPS-enabled Nginx container, in addition to mounting the verification directory, you must also mount the SSL certificate directory.

1
2
3
4
5
6
7
8
docker run -d \
--name your-nginx-container \
-p 80:80 \
-p 443:443 \
-v /mydata/certbot/www:/var/www/certbot \
-v /mydata/certbot/ssl:/etc/letsencrypt \
-v /path/to/your/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:latest

Miscellaneous Notes

  1. The default Azure domain name itself is free. However, the virtual machine must be associated with a public IP address, and this IP resource incurs costs based on its type and allocation method.

  2. Let's Encrypt certificates are valid for 90 days and must be renewed regularly. One common solution is to set up a cron job for this, though I don't currently have this requirement. The renewal command simply replaces certonly in Step 4️⃣ with renew.

  3. Q: Does our Nginx need to keep serving the /.well-known/acme-challenge path? Are there any security risks in doing so?

    A: To enable automatic renewal of Let's Encrypt certificates, persistently serving the /.well-known/acme-challenge path is necessary and standard practice. The files under this path are public, temporary files used for verification and contain no sensitive information. You don't need to worry excessively about this.

  4. In Step 4️⃣, a container is started solely to execute a Certbot command, hence the --rm parameter is used. There's no need to configure it in docker compose.

  5. Certbot uses ports 80/443 for verification and cannot use other custom ports.

  6. The method we used to request the certificate is called HTTP-01 challenge, which is the most common approach. Other methods like DNS-01 challenge also exist; refer to the official documentation.

References

  • LLM