Options -Indexes
DirectoryIndex index.html index.htm

# This is a static site. No PHP is used anywhere, so refuse to execute it at all.
<FilesMatch "\.(php[0-9]?|phtml|phar|pht|phps|cgi|pl|py|exe|so)$">
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Order allow,deny
    Deny from all
  </IfModule>
</FilesMatch>

<FilesMatch "^\.(env.*|git.*|htpasswd|user\.ini)$">
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
</FilesMatch>

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule \.(sql|sqlite|db|bak|backup|old|orig|swp|log|ini|sh|pem|key|zip|tar|gz|tgz)$ - [F,NC,L]
  RewriteRule ^(wp-admin|wp-includes|wp-content)(/|$) - [F,NC,L]
</IfModule>

<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

# Clean URLs: /about.html is redirected to /about, and /index.html to /.
# The extensionless path is then served from the matching .html file.
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /

  RewriteCond %{THE_REQUEST} \s/+index\.html[\s?] [NC]
  RewriteRule ^ / [R=301,L]

  RewriteCond %{THE_REQUEST} \s/+(.+?)\.html[\s?] [NC]
  RewriteRule ^ /%1 [R=301,L]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME}.html -f
  RewriteRule ^(.+?)/?$ $1.html [L]
</IfModule>

# Pages must revalidate. The account-level .htaccess adds Vary: User-Agent, so a
# cached page is kept per browser and edits can otherwise take a long time to show.
<FilesMatch "\.html$">
  <IfModule mod_headers.c>
    Header set Cache-Control "no-cache, max-age=0, must-revalidate"
    Header unset Expires
    Header unset Pragma
  </IfModule>
</FilesMatch>
