129 lines
4.9 KiB
ApacheConf
129 lines
4.9 KiB
ApacheConf
# --------------------------------
|
|
# FileRise portable .htaccess
|
|
# --------------------------------
|
|
Options -Indexes -Multiviews
|
|
DirectoryIndex index.html
|
|
|
|
# Allow PATH_INFO for routes like /webdav.php/foo/bar
|
|
AcceptPathInfo On
|
|
|
|
# ---------------- Security: dotfiles ----------------
|
|
<IfModule mod_authz_core.c>
|
|
# Block direct access to dotfiles like .env, .gitignore, etc.
|
|
<FilesMatch "^\..*">
|
|
Require all denied
|
|
</FilesMatch>
|
|
</IfModule>
|
|
|
|
# ---------------- Rewrites ----------------
|
|
<IfModule mod_rewrite.c>
|
|
RewriteEngine On
|
|
|
|
# 0) Let ACME http-01 pass BEFORE any other rule (needed for auto-renew)
|
|
RewriteCond %{REQUEST_URI} ^/.well-known/acme-challenge/
|
|
RewriteRule - - [L]
|
|
|
|
# 1) Block hidden files/dirs anywhere EXCEPT .well-known (path-aware)
|
|
# Prevents requests like /.env, /.git/config, /.ssh/id_rsa, etc.
|
|
RewriteRule "(^|/)\.(?!well-known/)" - [F]
|
|
RewriteRule ^portal/([A-Za-z0-9_-]+)$ portal.html?slug=$1 [L,QSA]
|
|
|
|
# 2) Deny direct access to PHP except the API endpoints and WebDAV front controller
|
|
# - allow /api/*.php (API endpoints)
|
|
# - allow /api.php (ReDoc/spec page)
|
|
# - allow /webdav.php (SabreDAV front)
|
|
RewriteCond %{REQUEST_URI} !^/api/ [NC]
|
|
RewriteCond %{REQUEST_URI} !^/api\.php$ [NC]
|
|
RewriteCond %{REQUEST_URI} !^/webdav\.php$ [NC]
|
|
RewriteRule \.php$ - [F,L]
|
|
|
|
# 3) Never redirect local/dev hosts
|
|
RewriteCond %{HTTP_HOST} ^(localhost|127\.0\.0\.1|fr\.local|192\.168\.[0-9]+\.[0-9]+)$ [NC]
|
|
RewriteRule ^ - [L]
|
|
|
|
# 4) HTTPS redirect (enable ONE of these, comment the other)
|
|
|
|
# A) Direct TLS on this server
|
|
#RewriteCond %{HTTPS} !=on
|
|
#RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
|
|
|
# B) Behind reverse proxy that sets X-Forwarded-Proto
|
|
#RewriteCond %{HTTP:X-Forwarded-Proto} =http [OR]
|
|
#RewriteCond %{HTTP:X-Forwarded-Proto} ^$
|
|
#RewriteCond %{HTTPS} !=on
|
|
#RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
|
|
|
# 5) Mark versioned assets (?v=...) with env flag for caching rules below
|
|
RewriteCond %{QUERY_STRING} (^|&)v= [NC]
|
|
RewriteRule ^ - [E=IS_VER:1]
|
|
</IfModule>
|
|
|
|
# ---------------- MIME types ----------------
|
|
<IfModule mod_mime.c>
|
|
AddType font/woff2 .woff2
|
|
AddType font/woff .woff
|
|
AddType image/svg+xml .svg
|
|
AddType application/javascript .mjs
|
|
</IfModule>
|
|
|
|
# ---------------- Security headers ----------------
|
|
<IfModule mod_headers.c>
|
|
Header always set X-Frame-Options "SAMEORIGIN"
|
|
Header always set X-XSS-Protection "1; mode=block"
|
|
Header always set X-Content-Type-Options "nosniff"
|
|
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
|
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
|
Header always set X-Download-Options "noopen"
|
|
Header always set Expect-CT "max-age=86400, enforce"
|
|
Header always set Cross-Origin-Resource-Policy "same-origin"
|
|
Header always set X-Permitted-Cross-Domain-Policies "none"
|
|
|
|
# HSTS only when HTTPS (safe for .htaccess)
|
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
|
|
|
|
# CSP — keep this SHA-256 in sync with your inline pre-theme script
|
|
Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; frame-ancestors 'self'; object-src 'none'; script-src 'self' 'sha256-ajmGY+5VJOY6+8JHgzCqsqI8w9dCQfAmqIkFesOKItM='; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; connect-src 'self'; media-src 'self' blob:; worker-src 'self' blob:; form-action 'self'"
|
|
</IfModule>
|
|
|
|
# ---------------- Caching ----------------
|
|
<IfModule mod_headers.c>
|
|
# HTML/PHP: no cache
|
|
<FilesMatch "\.(html?|php)$">
|
|
Header setifempty Cache-Control "no-cache, no-store, must-revalidate"
|
|
Header setifempty Pragma "no-cache"
|
|
Header setifempty Expires "0"
|
|
</FilesMatch>
|
|
|
|
# version.js: never cache
|
|
<FilesMatch "^js/version\.js$">
|
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
Header set Pragma "no-cache"
|
|
Header set Expires "0"
|
|
</FilesMatch>
|
|
|
|
# JS/CSS: long cache if ?v= present, else 1h
|
|
<FilesMatch "\.(?:m?js|css)$">
|
|
Header set Cache-Control "public, max-age=31536000, immutable" env=IS_VER
|
|
Header set Cache-Control "public, max-age=3600, must-revalidate" env=!IS_VER
|
|
</FilesMatch>
|
|
|
|
# Images/fonts: long cache if ?v= present, else 7d
|
|
<FilesMatch "\.(?:png|jpe?g|gif|webp|svg|ico|woff2?|ttf|otf)$">
|
|
Header set Cache-Control "public, max-age=31536000, immutable" env=IS_VER
|
|
Header set Cache-Control "public, max-age=604800" env=!IS_VER
|
|
</FilesMatch>
|
|
</IfModule>
|
|
|
|
# ---------------- Compression ----------------
|
|
<IfModule mod_brotli.c>
|
|
AddOutputFilterByType BROTLI_COMPRESS text/html text/css application/javascript application/json image/svg+xml
|
|
</IfModule>
|
|
<IfModule mod_deflate.c>
|
|
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json image/svg+xml
|
|
</IfModule>
|
|
|
|
# ---------------- Disable TRACE ----------------
|
|
<IfModule mod_rewrite.c>
|
|
RewriteCond %{REQUEST_METHOD} ^TRACE
|
|
RewriteRule .* - [F]
|
|
</IfModule> |