How to Set Up HTTPS
Secure your website with SSL/TLS encryption
TL;DR
TL;DR (20 minutes):
For Vercel/Netlify/Cloudflare Pages: HTTPS is automatic, just deploy. For custom servers: use Certbot to get free Let's Encrypt certificates. Enable HTTP-to-HTTPS redirects and add HSTS headers. Test with SSL Labs to verify your configuration scores A or higher.
Prerequisites
- A registered domain name pointing to your server or platform
- Access to DNS settings for your domain
- For manual setup: SSH access to your server with sudo privileges
- Your website already deployed and accessible via HTTP
Why HTTPS Matters
HTTPS encrypts all data between your users and your server. Without it:
- Passwords and data exposed - Anyone on the network can read form submissions
- SEO penalty - Google ranks HTTP sites lower than HTTPS
- Browser warnings - Chrome shows "Not Secure" for HTTP sites
- Features blocked - Service workers, geolocation, and other APIs require HTTPS
- No HTTP/2 - Modern performance features need HTTPS
Option 1: Platform-Managed SSL (Easiest)
Most modern hosting platforms handle SSL automatically:
Vercel
SSL is automatic for all deployments. No configuration needed.
# Just deploy - SSL is automatic
vercel --prod
# For custom domains, add in Vercel dashboard
# Settings > Domains > Add
# SSL certificate provisions automatically within minutes
Netlify
SSL is automatic with Let's Encrypt certificates.
# Deploy and SSL is automatic
netlify deploy --prod
# For custom domains:
# Site settings > Domain management > Add custom domain
# HTTPS section > Verify DNS > Provision certificate
Cloudflare Pages
# SSL is automatic when you connect your domain
# Pages > Your project > Custom domains > Add
# Cloudflare provisions certificate automatically
Platform SSL Benefits: Automatic renewal, no server configuration, includes edge caching, and handles certificate chain properly.
Option 2: Let's Encrypt with Certbot (Manual Server)
For VPS, dedicated servers, or self-hosted applications:
Install Certbot
# Ubuntu/Debian
sudo apt update
sudo apt install certbot
# For Nginx
sudo apt install python3-certbot-nginx
# For Apache
sudo apt install python3-certbot-apache
# CentOS/RHEL
sudo dnf install certbot python3-certbot-nginx
Obtain Certificate (Nginx)
# Certbot configures Nginx automatically
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Follow the prompts:
# - Enter email for renewal notices
# - Agree to terms of service
# - Choose whether to redirect HTTP to HTTPS (recommended: yes)
Obtain Certificate (Apache)
# Certbot configures Apache automatically
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
Set Up Automatic Renewal
# Test renewal process
sudo certbot renew --dry-run
# Certbot installs a cron job or systemd timer automatically
# Verify it exists:
systemctl list-timers | grep certbot
# Or check crontab:
cat /etc/cron.d/certbot
Option 3: Manual Nginx Configuration
If you prefer manual control or need custom configuration:
Get certificates with standalone mode
# Stop your web server temporarily
sudo systemctl stop nginx
# Get certificate
sudo certbot certonly --standalone -d yourdomain.com -d www.yourdomain.com
# Certificates saved to:
# /etc/letsencrypt/live/yourdomain.com/fullchain.pem
# /etc/letsencrypt/live/yourdomain.com/privkey.pem
Configure Nginx for HTTPS
# /etc/nginx/sites-available/yourdomain.com
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
# HTTPS server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL certificates
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# SSL configuration (Mozilla Intermediate)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS (enable after testing)
add_header Strict-Transport-Security "max-age=63072000" always;
# Your site configuration
root /var/www/yourdomain.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Test and reload Nginx
# Test configuration
sudo nginx -t
# Reload if test passes
sudo systemctl reload nginx
Enable HSTS (HTTP Strict Transport Security)
HSTS tells browsers to always use HTTPS, even if a user types HTTP:
Vercel (vercel.json)
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Strict-Transport-Security",
"value": "max-age=63072000; includeSubDomains; preload"
}
]
}
]
}
Netlify (_headers)
/*
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Next.js (next.config.js)
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
],
},
];
},
};
HSTS Warning:
Start with a short max-age (like 300 seconds) for testing. Once confirmed working, increase to 63072000 (2 years). HSTS is cached by browsers - mistakes can lock users out of your HTTP site!
Security Checklist
HTTPS Security Checklist
- SSL certificate installed and valid
- HTTP requests redirect to HTTPS (301 redirect)
- HSTS header enabled with appropriate max-age
- TLS 1.2 or higher (TLS 1.0/1.1 disabled)
- Strong cipher suites configured
- Certificate chain is complete (includes intermediates)
- No mixed content warnings on any page
- Certificate auto-renewal configured and tested
- CAA DNS record set (optional but recommended)
- OCSP stapling enabled (optional)
How to Verify It Worked
Browser check
Visit your site and look for the padlock icon in the address bar. Click it to view certificate details.
SSL Labs test
Run a comprehensive test at ssllabs.com/ssltest. Aim for an A or A+ grade.
# What the grades mean:
# A+ = Excellent (HSTS enabled)
# A = Good (secure configuration)
# B = Adequate (minor issues)
# C-F = Problems that need fixing
Command line verification
# Check certificate details
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -dates
# Check redirect
curl -I http://yourdomain.com
# Should show: HTTP/1.1 301 Moved Permanently
# Location: https://yourdomain.com/
# Check HSTS header
curl -I https://yourdomain.com | grep -i strict
Check for mixed content
Open browser DevTools (F12) > Console. Look for mixed content warnings. The page must load all resources over HTTPS.
Common Errors and Troubleshooting
ERR_CERT_AUTHORITY_INVALID
# Certificate not trusted - usually missing intermediate certificates
# Fix for Nginx - use fullchain.pem, not just cert.pem:
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
ERR_SSL_PROTOCOL_ERROR
# Check that SSL is properly configured
sudo nginx -t
# Check Nginx is listening on 443
sudo ss -tlnp | grep 443
# Check firewall allows HTTPS
sudo ufw status
sudo ufw allow 443/tcp
Certificate not renewing
# Test renewal manually
sudo certbot renew --dry-run
# Check certbot logs
sudo cat /var/log/letsencrypt/letsencrypt.log
# Common issue: port 80 blocked (needed for HTTP-01 challenge)
# Ensure your firewall allows port 80
Too many redirects
# Usually caused by redirect loop between HTTP and HTTPS
# Check if you have redirects in multiple places:
# - Web server config
# - Application code
# - CDN/proxy settings (Cloudflare, etc.)
# If behind Cloudflare, set SSL mode to "Full (strict)"
Mixed content after enabling HTTPS
# Find mixed content issues
# Browser Console will show warnings like:
# "Mixed Content: The page was loaded over HTTPS, but requested an insecure resource"
# Fix by updating URLs to HTTPS or using protocol-relative URLs:
# Change: http://example.com/image.png
# To: https://example.com/image.png
# Or: //example.com/image.png (inherits page protocol)
Is HTTPS really necessary for all websites?
Yes. HTTPS is required for SEO (Google ranks HTTPS sites higher), browser features (geolocation, service workers), user trust (browsers mark HTTP as "Not Secure"), and protecting any data your users submit. Even static sites benefit from HTTPS.
Are Let's Encrypt certificates as secure as paid certificates?
Yes, Let's Encrypt certificates provide the same encryption strength as paid certificates. The main differences are validation level (Let's Encrypt is domain validation only) and certificate lifetime (90 days vs 1-2 years). For most websites, Let's Encrypt is perfect.
::faq-item{question="Why does my site show "Not Secure" even with HTTPS?"} This usually indicates mixed content - your HTTPS page is loading resources (images, scripts, styles) over HTTP. Check browser console for mixed content warnings and update those URLs to HTTPS. See our mixed content fix guide. ::
How often do Let's Encrypt certificates need renewal?
Let's Encrypt certificates expire every 90 days, but Certbot automatically renews them when less than 30 days remain. The auto-renewal runs twice daily, so you typically never need to manually renew.
Should I use a wildcard certificate?
Wildcard certificates (*.yourdomain.com) are useful if you have many subdomains. For most sites with just www and root domain, separate certificates work fine. Wildcard certificates require DNS-01 validation which is slightly more complex to set up.
Run a free security scan to verify your HTTPS setup is properly configured.
Start Free Scan