šŸ”Building a Linux Web Server with Terraform & Ansible – Part 12: SSL Encryption

Now that our app is live and available through a custom domain, it’s time to take a crucial step toward production readiness: securing it with SSL encryption.


šŸ’” Why SSL Matters

SSL (Secure Sockets Layer) ensures that any data transferred between your users and your server is encrypted and private. Without it, all communication—like login credentials, form submissions, and API traffic—is transmitted in plain text and can be intercepted.

You’ll also notice modern browsers showing scary “Not Secure” warnings on HTTP-only websites. Google even considers HTTPS a ranking factor for SEO.


šŸ›  What Is Let’s Encrypt and Certbot?

  • Let’s Encrypt is a free, automated, and open Certificate Authority that issues SSL certificates.
  • Certbot is a tool that automates the process of:
    • Requesting a certificate
    • Installing it with Nginx
    • Renewing it automatically via cron

Best of all? It’s free and easy to integrate with Ansible.


šŸ“¦ Step 1: Create the Certbot Role

Let’s start by creating a new Ansible role to install and configure SSL with Certbot:

cd ansible
mkdir -p roles/certbot/tasks

āœļø Step 2: Configure the Role

Create roles/certbot/tasks/main.yml and add the following:

---
- name: Install certbot
  apt:
    name:
      - certbot
      - python3-certbot-nginx
    state: present
    force: yes
    update_cache: yes

- name: Register certbot
  shell: |
    certbot -n register --agree-tos --email {{ email }}
    touch /etc/letsencrypt/.registered
  args:
    creates: /etc/letsencrypt/.registered

- name: Setup cronjob for renewal
  cron:
    name: certbot-renewal
    job: "/bin/bash -lc '/usr/bin/certbot -q renew'"
    minute: "0"
    hour: "14"
    user: "{{ username }}"

- name: 'Get certificate'
  command: '/usr/bin/certbot -n --nginx certonly -d {{ hostname }} -d www.{{ hostname }}'
  args:
    creates: '/etc/letsencrypt/live/{{ hostname }}'
  ignore_errors: true

🧠 Breaking it Down

  • Certbot installation: Installs the necessary Certbot packages for Nginx.
  • Certbot registration: Registers an account with Let’s Encrypt using your email (required).
  • Cronjob setup: Ensures your certificate is automatically renewed daily.
  • SSL certificate request: Requests a certificate for both yourdomain.com and www.yourdomain.com.

We use certonly so Certbot gets the cert but doesn’t modify the Nginx config (we do that manually via template).


šŸ”— Step 3: Add the Role

In main.yml, include the role:

...
  roles:
  ...
 - role: roles/certbot

And in your vars.yml, add your email address:

email: <your email>

Then run the playbook:

play main.yml

🧪 Verifying Certbot Setup

SSH onto the server and check:

  1. Certificate files:
ls /etc/letsencrypt/live/{{ hostname }}

You should see files like:

fullchain.pem
privkey.pem
cert.pem
  1. Dry-run renewal:
sudo certbot renew --dry-run

šŸ“ Step 4: Update Nginx to Use SSL

Open your Nginx template at roles/app-nginx/templates/app.nginx.j2 and update it like so:

# Redirect HTTP to HTTPS
server {
    listen 80;
    listen [::]:80;

    server_name {{ hostname }};
    return 301 https://$host$request_uri;
}

# Serve app over HTTPS
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name {{ hostname }};

    ssl_certificate /etc/letsencrypt/live/{{ hostname }}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{{ hostname }}/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://unix:/run/{{ service_name }}/gunicorn.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

šŸ” Nginx Breakdown

  • The first server block redirects HTTP to HTTPS.
  • The second block:
    • Listens on port 443
    • Uses the Let’s Encrypt cert and private key
    • Proxies traffic to Gunicorn (like before)

šŸš€ Step 5: Run the Playbook Again

Apply the changes:

play main.yml

When it’s done, test your HTTPS endpoint:

curl https://<domain>/todos

You should now see the expected JSON response from your Flask API—this time encrypted and secure āœ…


āœ… Summary

In this article, we:

  • Installed and configured Certbot to obtain a free SSL certificate
  • Set up automated renewal via cron
  • Updated Nginx to redirect HTTP to HTTPS and use your new certificate
  • Validated everything with a secure curl request

You now have a fully encrypted Flask API running behind HTTPS—huge win for security and professionalism.


šŸ”œ Next Up…

In the final part of the series, we’ll use Terraform to configure monitoring and alerts so we can track the health of our droplet.

See you there! šŸ“ˆ

Leave a Reply

Your email address will not be published. Required fields are marked *