This block sends every variant of the site to https://example.com in one hop, keeping path and query string. With access to the vhosts, a port-80 Redirect permanent (mod_ssl and HTTPS) is simpler.
# /var/www/example/.htaccess: one public origin, https://example.com
# Needs: mod_rewrite; AllowOverride FileInfo; Options FollowSymLinks
RewriteEngine On
# Rule 1: any host other than the canonical one, on either scheme
RewriteCond %{HTTP_HOST} !^example\.com(:\d+)?$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
# Rule 2: the canonical host over plain HTTP, with no TLS proxy in front
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]Line 3 has no <IfModule> wrapper, so a server without mod_rewrite fails with a 500 rather than silently serving duplicates. Line 5 matches any other Host (www, an IP address, an old domain), and line 6 sends it straight to HTTPS, so http://www costs one hop. Lines 8 and 9 catch plain HTTP unless a TLS-terminating load balancer says otherwise; delete line 9 if none sits in front, since any client can send that header. Query strings pass through:
http://example.com/?id=7 301 https://example.com/?id=7 http://www.example.com/?id=7 301 https://example.com/?id=7 https://WWW.Example.com/ 301 https://example.com/ https://example.com/ 200 http://www.example.com/caf%C3%A9 301 https://example.com/caf%c3%a9 http://example.com/ (proxied) 200
Leave off the NE flag many copies add: %{REQUEST_URI} is decoded, and mod_rewrite re-encodes it (the café line) unless NE is set; with it, /a%20b produced Location: https://example.com/a b. Let's Encrypt 1,144 's HTTP-01 check follows redirects to HTTPS, so renewals need no exemption. Add HSTS once every name serves HTTPS (Canonical HTTPS Block).