Introduction: Why HTTPS Is No Longer Optional
In 2026, HTTPS is not a nice-to-have — it is a baseline requirement for every website. Google Chrome labels all HTTP sites as "Not Secure" with a prominent red warning in the address bar. Google Search uses HTTPS as a ranking signal, giving secure sites a measurable SEO advantage. Modern web APIs like geolocation, service workers, and HTTP/2 require HTTPS. And most importantly, HTTPS protects your users from eavesdropping, data tampering, and man-in-the-middle attacks on every page of your site.
But simply having an SSL certificate is not enough. Your site needs to enforce HTTPS everywhere: redirect all HTTP traffic to HTTPS, enable HSTS headers to prevent downgrade attacks, and fix mixed content issues that can break your secure pages. This guide covers every step of the process, from basic redirects through HSTS preloading, with configurations for both Nginx and Apache.
Step 1: HTTP to HTTPS Redirect
The first step is ensuring that every HTTP request is redirected to its HTTPS equivalent with a 301 Permanent Redirect. This tells browsers and search engines that the HTTPS version is the canonical URL.
Nginx Configuration
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 301 permanent redirect to HTTPS
return 301 https://$host$request_uri;
}
# HTTPS server block
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com/public_html;
index index.html index.php;
# ... rest of your configuration
}
Apache Configuration
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
Step 2: HSTS (HTTP Strict Transport Security)
HSTS is a security header that tells browsers: "This site should only be accessed over HTTPS. If someone tries to load it over HTTP, do not even make the request — upgrade it to HTTPS automatically in the browser." This eliminates the brief HTTP request that 301 redirects still allow.
How HSTS Works
HTTP request
to HTTPS
HSTS header
browser auto-upgrades
ever sent again
HSTS Header Configuration
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
HSTS Directives Explained
| Directive | Value | Meaning |
|---|---|---|
| max-age | 31536000 | Browser remembers the HSTS policy for 1 year (in seconds) |
| includeSubDomains | - | HSTS applies to all subdomains (api.example.com, blog.example.com, etc.) |
| preload | - | Signals that you want to be added to the browser HSTS preload list |
Step 3: HSTS Preload List
The HSTS preload list is maintained by Google and bundled into all major browsers (Chrome, Firefox, Safari, Edge). Once your domain is on this list, browsers will always use HTTPS for your domain — even on the very first visit, before any HSTS header is received.
Requirements for Preload Submission
- Serve a valid SSL certificate
- Redirect all HTTP traffic to HTTPS on the same host
- Serve the HSTS header on the base domain with max-age >= 31536000
- Include the
includeSubDomainsdirective - Include the
preloaddirective - All subdomains must also support HTTPS
Submit your domain at hstspreload.org. The review process takes several weeks, and once approved, your domain will be hardcoded into browser binaries.
Step 4: Fix Mixed Content
Mixed content occurs when an HTTPS page loads resources (images, scripts, stylesheets, fonts) over plain HTTP. Browsers block or warn about mixed content because an attacker could modify these insecure resources to compromise the otherwise secure page.
Types of Mixed Content
Active Mixed Content Blocked
Scripts, stylesheets, iframes, and XMLHttpRequests loaded over HTTP. These can modify the page DOM and are blocked by all modern browsers.
<script src="http://cdn.example.com/app.js">
Passive Mixed Content Warning
Images, audio, video, and other media loaded over HTTP. These cannot modify the page but can be replaced by an attacker (e.g., swapping an image).
<img src="http://cdn.example.com/photo.jpg">
Finding Mixed Content
# Open your site in Chrome, press F12, check the Console tab
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS,
but requested an insecure resource 'http://example.com/image.jpg'.
# Method 2: Command-line search in your codebase
$ grep -rn 'http://' /var/www/example.com/ \
--include="*.html" --include="*.php" --include="*.css" --include="*.js" \
| grep -v 'https://'
Fixing Mixed Content
| Current URL | Fix | Example |
|---|---|---|
http://example.com/style.css | Change to HTTPS | https://example.com/style.css |
http://cdn.example.com/app.js | Change to HTTPS | https://cdn.example.com/app.js |
http://example.com/image.jpg | Use protocol-relative | //example.com/image.jpg |
| Hardcoded in database (WordPress) | Search and replace | WP-CLI: wp search-replace 'http://example.com' 'https://example.com' |
Content-Security-Policy: upgrade-insecure-requests
As a safety net, you can add a CSP header that instructs browsers to automatically upgrade all HTTP resource requests to HTTPS:
add_header Content-Security-Policy "upgrade-insecure-requests" always;
# Apache
Header always set Content-Security-Policy "upgrade-insecure-requests"
# HTML meta tag (alternative)
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
upgrade-insecure-requests directive makes browsers silently upgrade HTTP URLs to HTTPS. This prevents mixed content warnings, but only if the HTTPS versions of those resources actually exist. Always fix the URLs in your code as well — do not rely solely on this header.
Step 5: Test Your HTTPS Configuration
Essential Testing Tools
SSL Labs (ssllabs.com)
Comprehensive SSL/TLS analysis. Tests cipher suites, protocol versions, certificate chain, HSTS, and known vulnerabilities. Aim for an A+ rating.
Security Headers (securityheaders.com)
Checks your security headers including HSTS, CSP, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy. Aim for an A rating or better.
Why No Padlock (whynopadlock.com)
Scans a page for mixed content issues that prevent the padlock icon from appearing. Lists every insecure resource URL for easy fixing.
HSTS Preload Checker
Verify your HSTS configuration meets all preload requirements before submitting to hstspreload.org.
Common HTTPS Mistakes and How to Avoid Them
Redirect Loop with Cloudflare Flexible SSL
If Cloudflare's SSL mode is set to "Flexible," Cloudflare connects to your server over HTTP. If your server redirects HTTP to HTTPS, you get an infinite loop. Fix: Set Cloudflare SSL mode to "Full (Strict)" and install a certificate on your origin server.
HSTS with Short max-age
Setting max-age to 300 (5 minutes) in production provides almost no protection. After 5 minutes, the browser forgets the HSTS policy and will attempt HTTP again. Use 31536000 (1 year) for production.
Missing www Redirect
Users may visit http://www.example.com, http://example.com, https://www.example.com, or https://example.com. All four variations should redirect to a single canonical URL (typically https://example.com or https://www.example.com).
Expired SSL Certificate
An expired certificate is worse than no certificate — browsers show a scary full-page warning that most users will not click through. Set up auto-renewal with Let's Encrypt and monitor certificate expiry dates.
Complete Nginx HTTPS Configuration Template
# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# www to non-www redirect
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
# Main HTTPS server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "upgrade-insecure-requests" always;
root /var/www/example.com/public_html;
index index.html index.php;
}
How Panelica Handles HTTPS
- Automatic Let's Encrypt issuance — SSL certificates are issued during domain creation
- Auto-renewal — certificates are renewed before expiry without intervention
- HTTP-to-HTTPS redirect — pre-configured in the Nginx template for every domain
- HSTS headers enabled — included in the default Nginx configuration
- TLS 1.2+ enforced — older, insecure TLS versions are disabled by default
Conclusion
Enforcing HTTPS everywhere is a multi-step process: redirect HTTP to HTTPS with 301, enable HSTS to prevent downgrade attacks, fix mixed content to maintain browser trust, and optionally submit to the HSTS preload list for maximum protection. Each step builds on the previous one to create a comprehensive HTTPS enforcement strategy. With free certificates from Let's Encrypt and modern web server configurations, there is no longer any excuse for serving content over plain HTTP. Your users deserve encrypted connections on every page, and search engines will reward you for providing them.