.htaccess guide - wip - 27-12-2024
After receiving some help i decided it would be nice to do something back.
I followed some of the stuff from sources below and put them together.
I wanted to get .htaccess working and ‘pretty urls’ props to Gwindalmir and szaimen
TESTED AND WORKS FOR ME!
Instead of https://nc.yourhostname.eu/index.php/apps/dashboard/
you get a nice https://nc.yourhostname.eu/apps/dashboard/
Also my website now shows “secure”
see here : (not sure if it’s related?)
Here’s the steps:
Copy the .htaccess file to a location you can write to:
sudo cp /snap/nextcloud/current/htdocs/.htaccess /var/snap/nextcloud/current/nextcloud/config/
Bind mount the .htaccess file back into the snap, this makes our changes readable by the snap:
sudo mount /var/snap/nextcloud/current/nextcloud/config/.htaccess /snap/nextcloud/current/htdocs/.htaccess -o bind
Now, edit the .htaccess file accordingly, copy this bit into your .htaccess file:
#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
ErrorDocument 403 /
ErrorDocument 404 /
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg|map|webm|mp4)$
RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
RewriteCond %{REQUEST_FILENAME} !/remote.php
RewriteCond %{REQUEST_FILENAME} !/public.php
RewriteCond %{REQUEST_FILENAME} !/cron.php
RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
RewriteCond %{REQUEST_FILENAME} !/status.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
RewriteCond %{REQUEST_FILENAME} !/robots.txt
RewriteCond %{REQUEST_FILENAME} !/updater/
RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
RewriteCond %{REQUEST_FILENAME} !/ocm-provider/
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteRule . index.php [PT,E=PATH_INFO:$1]
RewriteBase /
<IfModule mod_env.c>
SetEnv front_controller_active true
<IfModule mod_dir.c>
DirectorySlash off
</IfModule>
</IfModule>
</IfModule>
The complete .htaccess file should look something like this:
<IfModule mod_headers.c>
<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_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
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "no-referrer"
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"
Header onsuccess unset X-XSS-Protection
Header always set X-XSS-Protection "1; mode=block"
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>
</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>
</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
</IfModule>
<IfModule mod_dir.c>
DirectoryIndex index.php index.html
</IfModule>
<IfModule pagespeed_module>
ModPagespeed Off
</IfModule>
<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]
</IfModule>
# Clients like xDavv5 on Android, or Cyberduck, use chunked requests.
# When FastCGI or FPM is used with apache, requests arrive to Nextcloud without any content.
# This leads to the creation of empty files.
# The following directive will force the problematic requests to be buffered before being forwarded to Nextcloud.
# This way, the "Transfer-Encoding" header is removed, the "Content-Length" header is set, and the request content is proxied to Nextcloud.
# 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>
SetEnvIf 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
</IfModule>
AddDefaultCharset utf-8
Options -Indexes
#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
ErrorDocument 403 /
ErrorDocument 404 /
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg|map|webm|mp4)$
RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
RewriteCond %{REQUEST_FILENAME} !/remote.php
RewriteCond %{REQUEST_FILENAME} !/public.php
RewriteCond %{REQUEST_FILENAME} !/cron.php
RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
RewriteCond %{REQUEST_FILENAME} !/status.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
RewriteCond %{REQUEST_FILENAME} !/robots.txt
RewriteCond %{REQUEST_FILENAME} !/updater/
RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
RewriteCond %{REQUEST_FILENAME} !/ocm-provider/
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteRule . index.php [PT,E=PATH_INFO:$1]
RewriteBase /
<IfModule mod_env.c>
SetEnv front_controller_active true
<IfModule mod_dir.c>
DirectorySlash off
</IfModule>
</IfModule>
</IfModule>
Restart apache inside the snap so the changes take effect:
sudo snap restart nextcloud.apache
To enable the mount point automatically, add the following to your /etc/fstab file:
/var/snap/nextcloud/current/nextcloud/config/.htaccess /snap/nextcloud/current/htdocs/.htaccess none auto,bind,x-systemd.before=snap.nextcloud.apache.service,x-systemd.requires-mounts-for=/snap/nextcloud/current/,x-systemd.required-by=snap.nextcloud.apache.service 0 0
Then either reboot, or execute:
sudo systemctl daemon-reload; sudo systemctl restart local-fs.target
Note, this does rely on symlinks (/snap/nextcloud/current). Systemd mounting doesn’t work with symlinks, but that’s fine here, since the link itself wouldn’t change unless there was an update. The symlink is parsed only during evaluation (daemon-reload or reboot).
The result is a generated unit named snap-nextcloud-xxxxx-htdocs-.htaccess.mount
(for revision xxxxx of nextcloud). Assuming an update to the snap recreates the service unit files, then that mount unit should update accordingly.
Gotchas:
sudo nextcloud.occ maintenance:update:htaccess
still doesn’t work. I don’t know why.- Updates - I don’t know what will happen when the snap updates. Presumably your custom .htaccess file will still replace the original. However, you need to check to make sure the contents haven’t changed separately from what you added.
- Did get one error that’s new myself :
Unable to run check for JavaScript support. Please remedy or confirm manually if your webserver serves `.mjs` files using the JavaScript MIME type. To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule.
- Also :
Could not check for otf loading support. Please check manually if your webserver serves `.otf` files. To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule. For more details see the documentation ↗.
Any tips are welcome, don’t know if you can add co-writers on this forum or something?