Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 184 additions & 82 deletions .htaccess
Original file line number Diff line number Diff line change
@@ -1,101 +1,201 @@
<IfModule mod_headers.c>
<IfModule mod_setenvif.c>
<IfModule mod_fcgid.c>
SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
<IfModule mod_setenvif.c>
<IfModule mod_fcgid.c>
SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
</IfModule>
<IfModule mod_proxy_fcgi.c>
SetEnvIfNoCase Authorization "(.+)" HTTP_AUTHORIZATION=$1
</IfModule>
<IfModule mod_lsapi.c>
SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
</IfModule>
</IfModule>
<IfModule mod_proxy_fcgi.c>
SetEnvIfNoCase Authorization "(.+)" HTTP_AUTHORIZATION=$1
</IfModule>
<IfModule mod_lsapi.c>
SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION

<IfModule mod_env.c>
# Add security and privacy related headers
# Avoid doubled headers by unsetting headers in "onsuccess" table,
# then add headers to "always" table: https://github.com/nextcloud/server/pull/19002

<If "%{REQUEST_URI} =~ m#/login$#">
# Only on the login page we need any Origin or Referer header set.
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "same-origin"
</If>
<Else>
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "no-referrer"
</Else>

Header onsuccess unset X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"

Header onsuccess unset X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"

Header onsuccess unset X-Permitted-Cross-Domain-Policies
Header always set X-Permitted-Cross-Domain-Policies "none"

Header onsuccess unset X-Robots-Tag
Header always set X-Robots-Tag "noindex, nofollow"

SetEnv modHeadersAvailable true
</IfModule>
</IfModule>

<IfModule mod_env.c>
# Add security and privacy related headers
# Avoid doubled headers by unsetting headers in "onsuccess" table,
# then add headers to "always" table: https://github.com/nextcloud/server/pull/19002

<If "%{REQUEST_URI} =~ m#/login$#">
# Only on the login page we need any Origin or Referer header set.
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "same-origin"
</If>
<Else>
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "no-referrer"
</Else>

Header onsuccess unset X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"

Header onsuccess unset X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"

Header onsuccess unset X-Permitted-Cross-Domain-Policies
Header always set X-Permitted-Cross-Domain-Policies "none"

Header onsuccess unset X-Robots-Tag
Header always set X-Robots-Tag "noindex, nofollow"

SetEnv modHeadersAvailable true
</IfModule>

# Add cache control for static resources
<FilesMatch "\.(css|js|mjs|svg|gif|png|jpg|webp|ico|wasm|tflite)$">
<If "%{QUERY_STRING} =~ /(^|&)v=/">
Header set Cache-Control "max-age=15778463, immutable"
</If>
<Else>
Header set Cache-Control "max-age=15778463"
</Else>
</FilesMatch>

# Let browsers cache OTF and WOFF files for a week
<FilesMatch "\.(otf|woff2?)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>

# Add cache control for static resources
<FilesMatch "\.(css|js|mjs|svg|gif|png|jpg|webp|ico|wasm|tflite)$">
<If "%{QUERY_STRING} =~ /(^|&)v=/">
Header set Cache-Control "max-age=15778463, immutable"
</If>
<Else>
Header set Cache-Control "max-age=15778463"
</Else>
</FilesMatch>

# Let browsers cache OTF and WOFF files for a week
<FilesMatch "\.(otf|woff2?)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>
</IfModule>

<IfModule mod_php.c>
php_value mbstring.func_overload 0
php_value default_charset 'UTF-8'
php_value output_buffering 0
<IfModule mod_env.c>
SetEnv htaccessWorking true
</IfModule>
php_value mbstring.func_overload 0
php_value default_charset 'UTF-8'
php_value output_buffering 0
<IfModule mod_env.c>
SetEnv htaccessWorking true
</IfModule>
</IfModule>

<IfModule mod_mime.c>
AddType image/svg+xml svg svgz
AddType application/wasm wasm
AddEncoding gzip svgz
# Serve ESM javascript files (.mjs) with correct mime type
AddType text/javascript js mjs
AddType image/svg+xml svg svgz
AddType application/wasm wasm
AddEncoding gzip svgz
# Serve ESM javascript files (.mjs) with correct mime type
AddType text/javascript js mjs
</IfModule>

<IfModule mod_dir.c>
DirectoryIndex index.php index.html
DirectoryIndex index.php index.html
</IfModule>

<IfModule pagespeed_module>
ModPagespeed Off
ModPagespeed Off
</IfModule>

#############
#### Rewrites
#############

##
## Rule: Workaround for WebDAV with apache+php-cgi
##
## Context:
## - Sets the environment variable `HTTP_AUTHORIZATION` to the value of the `Authorization` request header
## - Always executed before and along with other rules (no `L` used)
## - XXX: *May* be replaced with an equivalent SetEnvIf in theory
## - XXX: SetEnvIf approach is already in use above for mod_proxy_cgi / mod_lsapi / mod_fcgid
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>

##
## Rule: Workaround for WebDAV with MS DavClnt
##
## Context:
## - DavClnt attempts an OPTIONS request against `/` instead of the specified endpoint
## - Redirects the client to the endpoint rather than the login page (which confuses DavClnt)
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} DavClnt
RewriteRule ^$ /remote.php/webdav/ [L,R=302]
</IfModule>

##
## Rule: Map the RFC 8615 / RFC 6764 compliant well-known URI for CardDAV to our Remote DAV endpoint
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
</IfModule>

##
## Rule: Map the RFC 8615 / RFC 6764 compliant well-known URI for CalDAV to our Remote DAV endpoint
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
</IfModule>

##
## Rule: Map /remote* --> /remote.php* including the query string
##
## Context:
## - XXX: `QSA` seems unnecessary (no-op) here (query string is passed by default when the replacement URI doesn't contain a query string)
## - XXX: Is this even used anymore? Seems a relic from <NC12
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^remote/(.*) remote.php [QSA,L]
</IfModule>

##
## Rule: Prevent access to non-public files
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} DavClnt
RewriteRule ^$ /remote.php/webdav/ [L,R=302]
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
RewriteRule ^remote/(.*) remote.php [QSA,L]
RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
RewriteRule ^\.well-known/(?!acme-challenge|pki-validation) /index.php [QSA,L]
RewriteRule ^ocm-provider/?$ index.php [QSA,L]
RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L]
RewriteEngine on
RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
</IfModule>

##
## Rule: Maps most RFC 8615 compliant well-known URIs to our main frontend controller (/index.php) by default
##
## Context:
## - Intentionally excludes URIs used for HTTPS certificate verifications
## - RFC 8555 / ACME HTTP Challenges (acme-challenge)
## - File-based Validations (pki-validation)
## - XXX: `QSA` seems unnecessary (no-op) here (query string is passed by default when the replacement URI doesn't contain a query string)
## - XXX: Sometimes we are using `/index.php` and other times `index.php` as our replacement URI; this may be incorrect
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^\.well-known/(?!acme-challenge|pki-validation) /index.php [QSA,L]
</IfModule>

##
## Rule: Map the ocm-provider handling to our main frontend controller (/index.php)
##
## Context:
## - XXX: `QSA` seems unnecessary (no-op) here (query string is passed by default when the replacement URI doesn't contain a query string)
## - XXX: Sometimes we are using `/index.php` and other times `index.php` as our replacement URI; this may be incorrect
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^ocm-provider/?$ index.php [QSA,L]
</IfModule>

##
## Rule: Prevent access to more non-public files
##
## Context:
## - XXX It may make sense to merge some of these with the others (i.e. the ones that don't need to be last)
##

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule>

# Clients like xDavv5 on Android, or Cyberduck, use chunked requests.
Expand All @@ -106,16 +206,18 @@
# Here are more information about the issue:
# - https://docs.cyberduck.io/mountainduck/issues/fastcgi/
# - https://docs.nextcloud.com/server/latest/admin_manual/issues/general_troubleshooting.html#troubleshooting-webdav

<IfModule mod_setenvif.c>
SetEnvIfNoCase Transfer-Encoding "chunked" proxy-sendcl=1
SetEnvIfNoCase Transfer-Encoding "chunked" proxy-sendcl=1
</IfModule>

# Apache disabled the sending of the server-side content-length header
# in their 2.4.59 patch updated which breaks some use-cases in Nextcloud.
# Setting ap_trust_cgilike_cl allows to bring back the usual behaviour.
# See https://bz.apache.org/bugzilla/show_bug.cgi?id=68973

<IfModule mod_env.c>
SetEnv ap_trust_cgilike_cl
SetEnv ap_trust_cgilike_cl
</IfModule>

AddDefaultCharset utf-8
Expand Down
Loading