87 lines
4.3 KiB
Plaintext
87 lines
4.3 KiB
Plaintext
# ============================================================================
|
|||
|
|
# visit.waterschurch.org — Apache configuration for the subdomain document root
|
||
|
|
# Copied to out/.htaccess by `npm run build` (scripts/postbuild.mjs).
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
Options -Indexes -MultiViews
|
||
|
|
DirectoryIndex index.html
|
||
|
|
ErrorDocument 404 /404.html
|
||
|
|
# cPanel's default 403 page does not exist in this document root; show our branded page instead (status stays 403).
|
||
|
|
ErrorDocument 403 /404.html
|
||
|
|
|
||
|
|
# --- Private configuration directory for the PHP API -----------------------
|
||
|
|
# Uncomment and set to the absolute path of the folder holding your .env file
|
||
|
|
# (OUTSIDE the document root). If omitted, the API looks for
|
||
|
|
# <parent of document root>/visit-private, e.g. /home/USER/visit-private.
|
||
|
|
# SetEnv VISIT_PRIVATE_DIR /home/USER/visit-private
|
||
|
|
|
||
|
|
<IfModule mod_rewrite.c>
|
||
|
|
RewriteEngine On
|
||
|
|
|
||
|
|
# Force HTTPS and the canonical non-www host
|
||
|
|
RewriteCond %{HTTPS} !=on [OR]
|
||
|
|
RewriteCond %{HTTP_HOST} ^www\.visit\.waterschurch\.org$ [NC]
|
||
|
|
RewriteRule ^(.*)$ https://visit.waterschurch.org/$1 [R=301,L]
|
||
|
|
|
||
|
|
# Never serve dot-files (except the ACME challenge folder used for SSL issuance)
|
||
|
|
RewriteCond %{REQUEST_URI} !^/\.well-known/
|
||
|
|
RewriteRule (^|/)\.(?!well-known) - [F,L]
|
||
|
|
|
||
|
|
# Next.js static export: serve /path as /path.html when the file exists
|
||
|
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||
|
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||
|
|
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
|
||
|
|
RewriteRule ^(.+?)/?$ /$1.html [L]
|
||
|
|
|
||
|
|
# Strip trailing slash on non-directories
|
||
|
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||
|
|
RewriteRule ^(.+)/$ /$1 [R=301,L]
|
||
|
|
</IfModule>
|
||
|
|
|
||
|
|
# --- Security headers -------------------------------------------------------
|
||
|
|
<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"
|
||
|
|
Header always set Permissions-Policy "geolocation=(self), camera=(), microphone=(), payment=()"
|
||
|
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" "expr=%{HTTPS} == 'on'"
|
||
|
|
# CSP is report-only until Waters Church confirms its tag/pixel list. See docs/DEPLOY-CPANEL.md.
|
||
|
|
Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com https://connect.facebook.net https://analytics.tiktok.com https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://www.facebook.com https://analytics.tiktok.com https://challenges.cloudflare.com; frame-src https://challenges.cloudflare.com; base-uri 'self'; form-action 'self' sms:; frame-ancestors 'self'"
|
||
|
|
|
||
|
|
# Immutable hashed assets
|
||
|
|
<FilesMatch "\.(js|css|woff2|avif|webp|jpg|jpeg|png|svg|ico)$">
|
||
|
|
Header set Cache-Control "public, max-age=31536000, immutable"
|
||
|
|
</FilesMatch>
|
||
|
|
# HTML and text files: always revalidate
|
||
|
|
<FilesMatch "\.(html|xml|txt|json)$">
|
||
|
|
Header set Cache-Control "public, max-age=0, must-revalidate"
|
||
|
|
</FilesMatch>
|
||
|
|
</IfModule>
|
||
|
|
|
||
|
|
# --- Compression -----------------------------------------------------------
|
||
|
|
<IfModule mod_deflate.c>
|
||
|
|
AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml font/woff2
|
||
|
|
</IfModule>
|
||
|
|
<IfModule mod_brotli.c>
|
||
|
|
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml
|
||
|
|
</IfModule>
|
||
|
|
|
||
|
|
# --- MIME types some cPanel builds miss -------------------------------------
|
||
|
|
AddType image/avif .avif
|
||
|
|
AddType image/webp .webp
|
||
|
|
AddType font/woff2 .woff2
|
||
|
|
|
||
|
|
# --- Expires fallback (when mod_headers is unavailable) ---------------------
|
||
|
|
<IfModule mod_expires.c>
|
||
|
|
ExpiresActive On
|
||
|
|
ExpiresByType image/avif "access plus 1 year"
|
||
|
|
ExpiresByType image/webp "access plus 1 year"
|
||
|
|
ExpiresByType image/jpeg "access plus 1 year"
|
||
|
|
ExpiresByType image/png "access plus 1 year"
|
||
|
|
ExpiresByType image/svg+xml "access plus 1 year"
|
||
|
|
ExpiresByType font/woff2 "access plus 1 year"
|
||
|
|
ExpiresByType text/css "access plus 1 year"
|
||
|
|
ExpiresByType application/javascript "access plus 1 year"
|
||
|
|
ExpiresByType text/html "access plus 0 seconds"
|
||
|
|
</IfModule>
|