AWS

HTTPS on AWS Lightsail: Setting Up Let's Encrypt with Apache and Route 53

Step-by-step guide to configuring a custom subdomain with Route 53 and securing an AWS Lightsail instance with a free TLS certificate using Let's Encrypt and Certbot.

Alexandre Agius

Alexandre Agius

AWS Solutions Architect

5 min read
Share:

You just deployed an app on AWS Lightsail. It works on the public IP. Now you want a proper domain with HTTPS. Here’s exactly how to do it — from DNS record to trusted certificate — in under 10 minutes.

The Starting Point

You have:

  • An AWS Lightsail instance running Apache on Ubuntu
  • A Route 53 hosted zone (e.g., example.com)
  • The instance’s public IP address

You want:

  • A subdomain like myapp.example.com pointing to your instance
  • A valid TLS certificate so browsers trust your site

Step 1: Create the DNS Record in Route 53

First, find your hosted zone ID:

aws route53 list-hosted-zones-by-name \
  --dns-name "example.com" \
  --max-items 1

Then create an A record pointing your subdomain to the Lightsail instance’s public IP:

aws route53 change-resource-record-sets \
  --hosted-zone-id Z0123456789ABCDEF \
  --change-batch '{
    "Changes": [
      {
        "Action": "CREATE",
        "ResourceRecordSet": {
          "Name": "myapp.example.com",
          "Type": "A",
          "TTL": 300,
          "ResourceRecords": [
            { "Value": "203.0.113.42" }
          ]
        }
      }
    ]
  }'

The status will show PENDING — DNS propagation typically completes within 30–60 seconds for Route 53. Verify with:

dig myapp.example.com

At this point, http://myapp.example.com should resolve to your instance. But if you try https://, you’ll get a browser error.

Step 2: The Certificate Problem

When you navigate to https://myapp.example.com, the browser shows:

Your connection is not private NET::ERR_CERT_COMMON_NAME_INVALID

This happens because the existing TLS certificate on your instance doesn’t include myapp.example.com in its Subject Alternative Names (SANs). The certificate was issued for a different domain — or it’s a self-signed default certificate.

The fix: issue a proper certificate that matches your domain.

Step 3: Identify Your Web Server

SSH into your Lightsail instance and check what’s listening on ports 80 and 443:

sudo ss -tlnp | grep -E '80|443'

If you see apache2 in the output:

LISTEN  0  511  *:80   *:*  users:(("apache2",pid=1461,fd=4)...)
LISTEN  0  511  *:443  *:*  users:(("apache2",pid=1461,fd=6)...)

Your web server is Apache. If you see nginx instead, adjust the certbot command accordingly.

Step 4: Install the Certificate with Certbot

Run certbot with the Apache plugin:

sudo certbot --apache -d myapp.example.com

Certbot will:

  1. Verify you own the domain (HTTP-01 challenge)
  2. Obtain a certificate from Let’s Encrypt
  3. Ask which virtual host to deploy it to

If certbot can’t auto-detect the right vhost, it will prompt you:

Which virtual host would you like to choose?
1: 000-default.conf               |       | Enabled
2: default-ssl.conf               | HTTPS | Enabled
Select the appropriate number [1-2]:

Select the HTTPS vhost (in this case, 2 for default-ssl.conf). Certbot deploys the certificate and configures an HTTP-to-HTTPS redirect automatically.

If certbot isn’t installed

On Ubuntu/Debian:

sudo apt update && sudo apt install certbot python3-certbot-apache -y

If you’re using Nginx instead

sudo certbot --nginx -d myapp.example.com

Step 5: Verify

Open https://myapp.example.com in your browser. You should see a valid certificate with no warnings.

You can also verify from the command line:

curl -I https://myapp.example.com

Check the certificate details:

echo | openssl s_client -servername myapp.example.com \
  -connect myapp.example.com:443 2>/dev/null | openssl x509 -noout -dates -subject

Auto-Renewal

Certbot sets up a systemd timer (or cron job) for automatic renewal. Let’s Encrypt certificates expire after 90 days, but certbot renews them well before that.

Verify the timer is active:

sudo systemctl list-timers | grep certbot

You can test renewal with a dry run:

sudo certbot renew --dry-run

Common Gotchas

“The nginx plugin is not working” — You’re running Apache, not Nginx. Use --apache instead of --nginx. Check with sudo ss -tlnp to confirm which server is running.

“Could not find a usable ‘nginx’ binary” — Same issue. Certbot’s Nginx plugin requires Nginx to be installed. If your server runs Apache, use the Apache plugin.

DNS not resolving — Certbot’s HTTP-01 challenge requires the domain to resolve to your instance. Make sure the Route 53 record has propagated before running certbot. Use dig to verify.

Port 80 blocked — The HTTP-01 challenge needs port 80 open. Check your Lightsail networking tab — ensure port 80 is open to 0.0.0.0/0.

Lightsail firewall vs. OS firewall — Lightsail has its own firewall (configured in the console or via CLI) that’s separate from ufw or iptables on the instance. Both need to allow the traffic.

Cost

  • Route 53 hosted zone: $0.50/month
  • DNS queries: $0.40 per million queries
  • Let’s Encrypt certificate: Free
  • Certbot: Free and open source

No need for AWS Certificate Manager (ACM) here — ACM certificates can’t be exported to Lightsail instances directly. Let’s Encrypt is the simplest path for Lightsail.

Summary

StepWhatCommand
1Create DNS recordaws route53 change-resource-record-sets
2Identify web serversudo ss -tlnp | grep -E '80|443'
3Install certificatesudo certbot --apache -d myapp.example.com
4Verifycurl -I https://myapp.example.com
5Confirm auto-renewalsudo certbot renew --dry-run

From public IP to trusted HTTPS in 5 commands. No load balancer, no ACM, no CloudFront — just Route 53, Certbot, and 10 minutes.

Alexandre Agius

Alexandre Agius

AWS Solutions Architect

Passionate about AI & Security. Building scalable cloud solutions and helping organizations leverage AWS services to innovate faster. Specialized in Generative AI, serverless architectures, and security best practices.

Related Posts

Back to Blog