If we are hosting a web application on a Linux server, enabling HTTPS is one of the first things we should take care of before exposing the application to users.
One of the easiest ways to do this is by using Let’s Encrypt. It provides free SSL/TLS certificates, and with Certbot we can automate both certificate installation and renewal.
In this article, we will go step by step through the process of configuring a Let’s Encrypt certificate with Nginx. We will also look at certificate renewal and some common issues that can prevent the certificate from being generated or renewed successfully.
What We Are Going to Set Up
We will configure Nginx to serve our application over HTTPS using a certificate issued by Let’s Encrypt.
The setup will include:
A domain pointing to our server
Nginx configured as the web server or reverse proxy
A Let’s Encrypt SSL certificate
HTTPS access on port 443
HTTP to HTTPS redirection
Automatic certificate renewal
Prerequisites
For this guide, we will assume that:
We have a Linux server.
Ubuntu is being used as the operating system.
Nginx is installed or can be installed.
We have a domain name.
We have access to the DNS configuration for the domain.
We have sudo access to the server.
Ports 80 and 443 are accessible from the internet.
For the examples below, we will use:
Domain: example.com
Server IP: 203.0.113.10
Replace these values with the actual domain and server details.
Step 1: Point the Domain to the Server
Before requesting an SSL certificate, our domain needs to resolve to the server where Nginx is running.
In the DNS configuration, create an A record.
Type: A
Name: @
Value: 203.0.113.10
If we also want to support www.example.com, we can create another record:
Type: A
Name: www
Value: 203.0.113.10
Depending on the DNS provider, the interface will look different, but the concept remains the same.
We should verify that DNS is resolving correctly before moving forward.
From the server or our local machine, run:
nslookup example.com
or:
dig example.com
The returned IP address should match our server's public IP.
If DNS is not resolving correctly, there is no point proceeding with Certbot yet. Let's Encrypt needs to verify that we control the domain.
Step 2: Install Nginx
If Nginx isn't already installed, we can install it using:
sudo apt update
sudo apt install nginx -y
Once the installation is complete, check the service:
sudo systemctl status nginx
We should see that the service is running.
We can also verify the configuration:
sudo nginx -t
A successful configuration check should return something similar to:
syntax is ok
test is successful
Now open the domain in a browser:
http://example.com
At this stage, we should get the Nginx default page or our application, depending on how Nginx has been configured.
Step 3: Configure Nginx for the Domain
Before requesting the certificate, we should configure a server block for our domain.
Create a configuration file:
sudo nano /etc/nginx/sites-available/example.com
Add the following:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
The proxy_pass value should point to the application running behind Nginx.
For example, if our application is running on port 3000:
proxy_pass http://127.0.0.1:3000;
If the application is running on another server, we can use that server's address instead.
Step 4: Enable the Nginx Configuration
Create a symbolic link to enable the configuration:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
Then test the configuration:
sudo nginx -t
If everything looks correct, reload Nginx:
sudo systemctl reload nginx
Now verify that the domain is accessible:
http://example.com
We should make sure the application works correctly over HTTP before moving to HTTPS.
Step 5: Install Certbot
Now we can install Certbot and the Nginx plugin.
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
Verify the installation:
certbot --version
We should get the installed Certbot version as the output.
Certbot will communicate with Let's Encrypt, request the certificate and configure Nginx for HTTPS.
Step 6: Request the Let's Encrypt Certificate
Now we can request the certificate.
Run:
sudo certbot --nginx -d example.com -d www.example.com
Certbot will ask for some information, including an email address and agreement to the terms of service.
It will then communicate with Let's Encrypt and perform domain validation.
If the validation succeeds, Certbot will obtain the certificate and update the Nginx configuration.
One of the advantages of using the Nginx plugin is that we don't have to manually copy certificate paths into the Nginx configuration.
Step 7: Redirect HTTP to HTTPS
During the Certbot setup, we may be asked whether HTTP traffic should be redirected to HTTPS.
Choose the redirect option if we want all HTTP traffic to automatically use HTTPS.
After enabling the redirect, users visiting:
http://example.com
will automatically be redirected to:
https://example.com
This ensures that users always access the application through an encrypted connection.
Step 8: Verify the HTTPS Configuration
Open the following URL in a browser:
https://example.com
The browser should show the secure connection indicator.
We can also check the certificate from the command line:
openssl s_client -connect example.com:443 -servername example.com
This provides information about the certificate and TLS connection.
We can also check the Nginx configuration:
sudo nginx -t
If everything is configured correctly, Nginx should report:
syntax is ok
test is successful
Step 9: Check the Certificate
Certbot provides a convenient command to check the certificates currently installed on the server.
sudo certbot certificates
Example output:
Certificate Name: example.com
Domains: example.com www.example.com
Expiry Date: ...
Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
Certbot normally stores certificates under:
/etc/letsencrypt/
We generally shouldn't manually modify files inside this directory because Certbot manages the certificate lifecycle.
Step 10: Configure Automatic Renewal
Let's Encrypt certificates are short-lived and need to be renewed regularly.
The good part is that Certbot can handle renewal automatically.
First, check whether the Certbot renewal timer is active:
sudo systemctl status certbot.timer
We can also check the timers on the system:
systemctl list-timers | grep certbot
If the timer is configured correctly, Certbot will periodically check whether the certificate needs renewal.
Step 11: Test Certificate Renewal
We shouldn't wait until the certificate is about to expire to find out that automatic renewal doesn't work.
We can perform a dry run:
sudo certbot renew --dry-run
This performs a simulated renewal process without replacing the existing certificate.
A successful test should indicate that the renewal simulation completed successfully.
This is something worth testing after the initial setup and whenever we make significant changes to the Nginx or DNS configuration.
Common Problems
The installation itself is usually straightforward. Most problems occur during domain validation, Nginx configuration or certificate renewal.
Problem 1: Domain Doesn't Point to the Server
If Certbot reports that domain validation failed, the first thing we should check is DNS.
Run:
dig example.com
Make sure the returned IP address points to the correct server.
If DNS was changed recently, we may also need to wait for the DNS changes to propagate.
Problem 2: Port 80 Is Not Accessible
Let's Encrypt commonly needs to reach the server through HTTP during certificate validation.
Make sure port 80 is open.
On Ubuntu with UFW:
sudo ufw status
If required:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
If the server is running in a cloud environment, we also need to check the cloud firewall or security group.
Opening the port in UFW isn't enough if the cloud firewall is blocking the traffic.
Problem 3: Nginx Configuration Test Fails
If this command fails:
sudo nginx -t
we should fix the Nginx configuration before running Certbot.
The error message usually contains the configuration file and line number where the problem exists.
We can inspect the complete configuration using:
sudo nginx -T
This prints the complete Nginx configuration currently being loaded.
Problem 4: Too Many Redirects
After enabling HTTPS, we may sometimes encounter a redirect loop.
For example, the browser keeps switching between HTTP and HTTPS.
This usually happens when there is another reverse proxy or load balancer in front of Nginx and the original protocol isn't being handled correctly.
We should check:
Nginx redirect rules
Reverse proxy configuration
Load balancer configuration
X-Forwarded-Protoheaders
We should avoid adding multiple layers of HTTPS redirects without understanding how traffic flows through the infrastructure.
Problem 5: Certificate Renewal Fails
If automatic renewal fails, first check the existing certificates:
sudo certbot certificates
Then test renewal manually:
sudo certbot renew --dry-run
Check the Certbot logs if the problem isn't obvious:
sudo ls /var/log/letsencrypt/
The logs usually provide enough information to identify whether the issue is DNS, Nginx, port accessibility or certificate validation.
Useful Commands
Here are some commands we can keep handy when troubleshooting a Let's Encrypt and Nginx setup.
Check Nginx status:
sudo systemctl status nginx
Test Nginx configuration:
sudo nginx -t
Reload Nginx:
sudo systemctl reload nginx
Check certificates:
sudo certbot certificates
Test renewal:
sudo certbot renew --dry-run
Check Certbot timer:
systemctl list-timers | grep certbot
Check HTTPS certificate:
openssl s_client -connect example.com:443 -servername example.com
Check DNS:
dig example.com
A Few Things We Should Keep in Mind
Getting the certificate is only one part of enabling HTTPS.
We should also make sure that:
HTTP redirects to HTTPS.
Port 443 is accessible.
The certificate covers all required domains.
Automatic renewal is working.
Nginx configuration remains valid.
Application URLs use HTTPS where required.
Mixed-content issues are not introduced in the application.
HTTPS should be treated as part of the application's infrastructure rather than simply a certificate that we install once and forget about.
No comments:
Post a Comment