You deployed a web app on Fedora and the browser shows a red lock
You have a service running on Fedora. It responds to HTTP requests. You want to add HTTPS. You install Certbot. You run a command. The wizard asks for a mode. You pick standalone. The command fails with a port conflict. Or you pick webroot and Certbot asks for a path that does not exist. Or you get the certificate, but the web server configuration is still pointing to HTTP, and the browser refuses to connect.
The gap between obtaining a certificate and serving it securely is where most setups break. Certbot handles the certificate lifecycle. Your web server handles the traffic. They must agree on the file paths, the ports, and the renewal process. Fedora's strict security defaults add another layer. SELinux protects the certificate files. The firewall controls access to the challenge port. A working HTTPS setup requires coordinating all three.
How Certbot and Let's Encrypt actually work
Let's Encrypt is a Certificate Authority. It issues certificates that browsers trust. Certbot is a client that communicates with Let's Encrypt using the ACME protocol. The protocol is automated. Certbot proves you control the domain, and Let's Encrypt returns a certificate.
The proof happens via a challenge. The HTTP-01 challenge is the standard method. Certbot generates a random token. It must serve that token at a specific URL: http://yourdomain.com/.well-known/acme-challenge/TOKEN. Let's Encrypt's servers fetch that URL. If the token matches, ownership is verified.
This mechanism dictates how Certbot runs. The challenge requires port 80 to be accessible from the internet. It requires a web server to serve the token file. Certbot provides different modes to satisfy these requirements based on your environment.
Standalone mode spins up a temporary web server on port 80 to serve the token. This works only if no other service is using port 80. Webroot mode places the token in a directory that your existing web server already serves. Plugin modes like --nginx or --apache integrate directly with the web server configuration to handle the challenge and apply the certificate automatically.
Certbot stores certificates in /etc/letsencrypt/live/yourdomain.com/. This directory contains symlinks to the actual certificate files. The symlinks point to versioned files in /etc/letsencrypt/archive/. This structure allows Certbot to rotate certificates during renewal without breaking the web server configuration. The web server always reads from the live path. Certbot updates the symlinks after a successful renewal.
Check the firewall before running Certbot. The ACME challenge fails silently if port 80 is blocked.
Install Certbot and obtain a certificate
Install the Certbot package and the plugin for your web server. Fedora packages plugins separately. The plugin allows Certbot to manage the web server configuration and handle the challenge without stopping your service.
Here is how to install Certbot and the Nginx plugin.
sudo dnf install certbot certbot-nginx -y
# WHY: Installs the core certbot tool and the Nginx plugin.
# WHY: The plugin enables automatic configuration and challenge handling for Nginx.
Ensure the firewall allows HTTP traffic. The ACME challenge requires Let's Encrypt to reach port 80. If the firewall blocks port 80, the challenge fails.
Here is how to open port 80 and reload the firewall rules.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
# WHY: Adds the HTTP service to the permanent firewall configuration.
# WHY: Reloads the firewall to apply the new rule immediately.
Run Certbot with the web server plugin. The plugin will detect your server blocks, ask which domains to secure, and configure HTTPS automatically.
Here is how to run the interactive wizard for Nginx.
sudo certbot --nginx -d yourdomain.com
# WHY: Starts the Certbot wizard using the Nginx plugin.
# WHY: The -d flag specifies the domain. Add multiple -d flags for additional domains.
Certbot will prompt you to choose between redirecting HTTP to HTTPS or keeping both options. Redirecting is the recommended practice. It forces all traffic to use the secure connection.
Certbot creates the certificate files and updates the Nginx configuration. It also sets up a systemd timer for automatic renewal. The timer runs twice daily. It checks if the certificate is within 30 days of expiration. If it is, Certbot requests a renewal.
Verify the renewal timer is active.
systemctl status certbot.timer
# WHY: Checks the status of the automatic renewal timer.
# WHY: The timer must be active to prevent certificate expiration.
Reload the web server after renewal. Certificates update, but the process keeps the old keys in memory.
Verify the certificate and configuration
Confirm the certificate files exist and the web server is serving HTTPS. Check the live directory for the symlinks.
Here is how to list the certificate files for your domain.
ls -l /etc/letsencrypt/live/yourdomain.com/
# WHY: Lists the certificate files. The fullchain.pem and privkey.pem must exist.
# WHY: These files are symlinks to the current valid certificate.
Test the HTTPS connection. Use curl to check the response headers and the certificate chain.
Here is how to verify the HTTPS response and certificate details.
curl -I https://yourdomain.com
# WHY: Sends a HEAD request to the HTTPS endpoint.
# WHY: The output shows the HTTP status code and certificate information.
Look for HTTP/2 or HTTP/1.1 200 OK. If you see a connection error, the web server is not listening on port 443. If you see a certificate error, the web server is not configured to use the correct certificate files.
Check the web server logs for configuration errors. Nginx logs errors to /var/log/nginx/error.log. Apache logs errors to /var/log/httpd/error_log.
Run the web server config test before restarting. A syntax error in the HTTPS block can crash the service.
sudo nginx -t
# WHY: Tests the Nginx configuration for syntax errors.
# WHY: Returns "syntax is ok" if the configuration is valid.
Read the actual error before guessing. Configuration drift causes silent failures.
Common pitfalls and error messages
Standalone mode fails if a web server is running. The error message is explicit.
Error: Another program is already listening on port 80.
This error means Nginx, Apache, or another service is bound to port 80. Standalone mode cannot start its temporary server. Switch to the web server plugin or webroot mode. Do not stop the web server to use standalone mode unless you have no other option. Stopping the web server causes downtime.
The ACME challenge fails if the firewall blocks port 80. The error message indicates a connection failure.
Failed authorization procedure. yourdomain.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client
This error means Let's Encrypt could not reach your server. Check the firewall rules. Check if a cloud provider security group blocks port 80. Check if the domain DNS resolves to your server's IP address.
SELinux denies access if the context is wrong. Certbot usually sets the correct context. If you move certificate files manually, SELinux may block the web server from reading them.
Permission denied: '/etc/letsencrypt/live/yourdomain.com/privkey.pem'
This error in the web server log indicates SELinux is blocking access. Restore the default context.
sudo restorecon -Rv /etc/letsencrypt/
# WHY: Restores the default SELinux security contexts for the LetsEncrypt directory.
# WHY: Fixes permission errors caused by manual file moves or copies.
Rate limits apply if you fail too many times. Let's Encrypt limits the number of failed challenges per domain per week. If you hit the limit, you must wait. Use --dry-run to test without consuming quota.
sudo certbot --nginx -d yourdomain.com --dry-run
# WHY: Simulates the certificate issuance without contacting Let's Encrypt.
# WHY: Validates the configuration and challenge setup without risking rate limits.
Trust the package manager. Manual file edits drift, snapshots stay.
When to use Certbot modes and plugins
Use certbot --nginx when you are running Nginx and want automatic configuration and renewal.
Use certbot --apache when you are running Apache and want automatic configuration and renewal.
Use certbot certonly --webroot when you are running a custom web server or a language-specific framework that does not have a Certbot plugin.
Use certbot certonly --standalone when you have no web server running and need a certificate for a service that does not use HTTP, such as a mail server or a custom daemon.
Use certbot renew --dry-run when you want to test the renewal process without actually requesting a new certificate from Let's Encrypt.