diff --git a/config/apache/rewrites/feeds.conf b/config/apache/rewrites/feeds.conf index 565b58ad..8b62c124 100644 --- a/config/apache/rewrites/feeds.conf +++ b/config/apache/rewrites/feeds.conf @@ -1,7 +1,7 @@ -# Redirect old feed URLs +# Redirect old feed URLs. RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L] -# If we ask for /opds/all?query=xyz, rewrite that to the search page. +# If we ask for `/opds/all?query=xyz`, rewrite that to the search page. RewriteCond %{QUERY_STRING} \bquery= RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA] diff --git a/config/apache/rewrites/misc.conf b/config/apache/rewrites/misc.conf index 6c151199..b481d855 100644 --- a/config/apache/rewrites/misc.conf +++ b/config/apache/rewrites/misc.conf @@ -1,12 +1,12 @@ -# Favicon rewrites +# Favicon rewrites. RewriteRule ^/(apple-touch|android-chrome|favicon|mstile|safari-pinned|browserconfig|manifest)([^/]+)$ /images/favicons/$1$2 [L] -# Redirect tools +# Redirect the toolset to GitHub. RewriteRule ^/tools$ https://github.com/standardebooks/tools [R=302,L] -# Redirect latest version of the manual +# Redirect latest version of the manual. RewriteRule ^/manual/latest(.*) /manual/index.php?url=$1 [L] -# Rewrite rules for bulk downloads +# Rewrite rules for bulk downloads. RewriteRule ^/bulk-downloads/(.+\.zip)$ /bulk-downloads/download.php?path=$1 RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?class=$1 diff --git a/config/apache/standardebooks.org.conf b/config/apache/standardebooks.org.conf index bceb4729..9b998107 100644 --- a/config/apache/standardebooks.org.conf +++ b/config/apache/standardebooks.org.conf @@ -1,4 +1,4 @@ -# Global configuration; see https://securityheaders.com +# Global configuration; see . Header set X-Frame-Options "sameorigin" Header set X-Content-Type-Options "nosniff" Header set X-Xss-Protection "1; mode=block" @@ -16,7 +16,7 @@ AddOutputFilterByType deflate image/vnd.microsoft.icon image/x-icon TraceEnable off Protocols h2 h2c http/1.1 -# Set up caching directives for infrequently changed files +# Set up caching directives for infrequently changed files. ExpiresActive on ExpiresByType application/javascript "access plus 6 months" ExpiresByType text/javascript "access plus 6 months" @@ -30,21 +30,20 @@ ExpiresByType image/vnd.microsoft.icon "access plus 6 months" ExpiresByType image/x-icon "access plus 6 months" ExpiresByType text/css "access plus 6 months" -# These lines are a workaround for an Apache bug that prevents mod_deflate, etags, and ExpiresByType working at the same time. -# This is probably still broken in 18.04. See https://stackoverflow.com/questions/896974/apache-is-not-sending-304-response-if-mod-deflate-and-addoutputfilterbytype-is -# Can possibly be fixed in Ubuntu 22.04 using https://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag +# These lines are a workaround for an Apache bug that prevents `mod_deflate`, etags, and `ExpiresByType` working at the same time. +# This can only be fixed in Ubuntu 24.04 and later using . FileETag All RequestHeader edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\"" Header edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\"" -# SSL hardening; see https://mozilla.github.io/server-side-tls/ssl-config-generator/ +# SSL hardening; see . SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 SSLHonorCipherOrder on SSLCompression off SSLSessionTickets off SSLStaplingCache shmcb:/var/run/ocsp(128000) -# SSL Stapling should be off for testing to prevent errors in log files, and on for live +# SSL Stapling should be off for testing to prevent errors in log files, and on for live. SSLUseStapling on SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off @@ -94,50 +93,49 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites Header set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline';" - # Disable .htaccess files + # Disable `.htaccess` files. AllowOverride none - # Disable unneeded options + # Disable unneeded options. Options none - # Allow access to www/ + # Allow access to `www/`. Require all granted - # Pass HTTP Authorization headers to PHP-FPM + # Pass HTTP Authorization headers to PHP-FPM. CGIPassAuth on AddType application/x-mobi8-ebook .azw3 - # We explicitly set the content-type for items in the /vocab/ directory, because Apache doesn't set it for us, - # and we need a content-type header when using the "nosniff" header. See https://bugzilla.mozilla.org/show_bug.cgi?id=1547076 + # We explicitly set the content-type for items in the `/vocab/` directory, because Apache doesn't set it for us, and we need a `Content-Type` header when using the `Nosniff` header. See . Header set Content-Type "text/plain" - # Enable HTTP CORS so that browser-based readers like Readium can access opds and ebooks - # Allow fonts for newsletter emails - # See https://github.com/standardebooks/tools/issues/2 + # Enable HTTP CORS so that browser-based readers like Readium can access OPDS and ebooks. + # Allow fonts for newsletter emails. + # See . Header set Access-Control-Allow-Origin "*" - # We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS + # We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS. Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';" - # Remove www from requests + # Remove `www.` from requests. RewriteCond %{HTTP_HOST} ^www\.(.+) [NC] RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L] # PHP-FPM configuration - # See https://serverfault.com/questions/450628/apache-2-4-php-fpm-proxypassmatch/510784 + # See . - # Required for FPM to receive POST data sent with Transfer-Encoding: chunked + # Required for FPM to receive POST data sent with `Transfer-Encoding: chunked`. SetEnv proxy-sendcl 1 - # Forward all PHP requests to the php-fpm pool for this domain. + # Forward all PHP requests to the PHP-FPM pool for this domain. SetHandler "proxy:unix:///run/php/${domain}.sock|fcgi://${domain}" Header set Cache-Control "no-store" @@ -158,47 +156,45 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites RewriteCond %{HTTP_USER_AGENT} ChatGPT-User RewriteRule ^ - [L,R=429] - # In RewriteCond, RewriteRule gets evaluated BEFORE RewriteCond, so $1 refers to the first - # match in RewriteRule - # Rewrite POST /some/url -> POST /some/url/post.php + # In `RewriteCond`, `RewriteRule` gets evaluated *before `RewriteCond`, so `$1` refers to the first match in `RewriteRule`. + # Rewrite POST `/some/url` -> POST `/some/url/post.php`. RewriteCond expr "tolower(%{REQUEST_METHOD}) =~ /^(post|delete|put)$/" RewriteCond %{DOCUMENT_ROOT}/$1/%1.php -f RewriteRule ^([^\.]+)$ $1/%1.php [L] - # In case of 404, serve the 404 page specified by ErrorDocument, not the default FPM error page. - # Note that we can't use `ProxyErrorOverride on` because that catches ALL 4xx and 5xx HTTP headers - # and serves the default Apache page for them. + # In case of 404, serve the 404 page specified by `ErrorDocument`, not the default FPM error page. + # Note that we can't use `ProxyErrorOverride on` because that catches *all* 4xx and 5xx HTTP headers and serves the default Apache page for them. RewriteCond %{REQUEST_FILENAME} \.php$ RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f RewriteRule (.*) - [H=text/html] - # Received: /filename.php and /filename.php exists in filesystem; Result: 301 redirect to /filename and restart request + # Received `/filename.php` and `/filename.php` exists in filesystem -> 301 redirect to `/filename` and restart request. RewriteCond %{REQUEST_FILENAME} \.php$ RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -f RewriteRule ^/(.+)\.php$ /$1 [R=301,L] - # Received: /filename and /filename.php exists in filesystem; Result: change /filename to /filename.php and continue processing + # Received `/filename` and `/filename.php` exists in filesystem -> change `/filename` to `/filename.php` and continue request. RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-d RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI}.php -f RewriteRule ^(.+)$ $1.php [QSA] # End PHP-FPM configuration - # Received: /filename and /filename.xml exists in filesystem; Result: rewrite to /filename.xml + # Received: `/filename` and `/filename.xml` exists in filesystem -> rewrite to `/filename.xml` and continue request. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.xml -f RewriteRule (.*) $1.xml - # Remove trailing slashes + # Remove trailing slashes. RewriteRule ^/(.+?)/$ /$1 [R=301,L] - # Redirect ToC of XHTML representation of books + # Redirect ToC of XHTML representation of books. RewriteRule ^/ebooks/(.+?)/text$ /ebooks/$1/toc.xhtml [L] - # Received: /filename and /filename.xhtml exists in filesystem; Result: rewrite to /filename.xhtml + # Received: `/filename` and `/filename.xhtml` exists in filesystem -> rewrite to `/filename.xhtml` and continue request. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.xhtml -f RewriteRule (.*) $1.xhtml - # Redirect index pages + # Redirect index pages. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.php -f RewriteRule (.*) $1/index.php @@ -207,7 +203,7 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.xml -f RewriteRule (.*) $1/index.xml - # Remove newline characters inserted by accident in some email clients + # Remove newline characters inserted by accident in some email clients. RewriteRule ^(.*)\r\n[\ ]?(.*)$ $1$2 [R=301,N] RewriteRule ^(.*)/r/n[\ ]?(.*)$ $1$2 [R=301,N] RewriteRule ^(.*)/[rn]$ $1 [R=301,N] @@ -221,24 +217,24 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites Include ${conf_rewrite_root}/users.conf Include ${conf_rewrite_root}/projects.conf - # Specific config for /ebooks///downloads + # `XSendFile` configuration for `/ebooks///downloads`. - # Both directives are required + # Both directives are required. XSendFile on XSendFilePath ${web_root}/www/ebooks - # Specific config for /bulk-downloads + # `XSendFile` configuration for `/bulk-downloads`. - # Both directives are required + # Both directives are required. XSendFile on XSendFilePath ${web_root}/www/bulk-downloads - # Specific config for /feeds + # `XSendFile` configuration for `/feeds`. - # This must be defined at the top level /feeds/ directory - # Both directives are required + # This must be defined at the top level `/feeds/` directory. + # Both directives are required. XSendFile on XSendFilePath ${web_root}/www/feeds diff --git a/config/apache/standardebooks.test.conf b/config/apache/standardebooks.test.conf index acdf89ea..04c1bc0f 100644 --- a/config/apache/standardebooks.test.conf +++ b/config/apache/standardebooks.test.conf @@ -1,4 +1,4 @@ -# Global configuration; see https://securityheaders.com +# Global configuration; see . Header set X-Frame-Options "sameorigin" Header set X-Content-Type-Options "nosniff" Header set X-Xss-Protection "1; mode=block" @@ -16,7 +16,7 @@ AddOutputFilterByType deflate image/vnd.microsoft.icon image/x-icon TraceEnable off Protocols h2 h2c http/1.1 -# Set up caching directives for infrequently changed files +# Set up caching directives for infrequently changed files. ExpiresActive on ExpiresByType application/javascript "access plus 6 months" ExpiresByType text/javascript "access plus 6 months" @@ -30,9 +30,8 @@ ExpiresByType image/vnd.microsoft.icon "access plus 6 months" ExpiresByType image/x-icon "access plus 6 months" ExpiresByType text/css "access plus 6 months" -# These lines are a workaround for an Apache bug that prevents mod_deflate, etags, and ExpiresByType working at the same time. -# This is probably still broken in 18.04. See https://stackoverflow.com/questions/896974/apache-is-not-sending-304-response-if-mod-deflate-and-addoutputfilterbytype-is -# Can possibly be fixed in Ubuntu 22.04 using https://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag +# These lines are a workaround for an Apache bug that prevents `mod_deflate`, etags, and `ExpiresByType` working at the same time. +# This can only be fixed in Ubuntu 24.04 and later using . FileETag All RequestHeader edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\"" Header edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\"" @@ -44,8 +43,8 @@ SSLHonorCipherOrder on SSLCompression off SSLSessionTickets off SSLStaplingCache shmcb:/var/run/ocsp(128000) -# SSL Stapling should be off for testing to prevent errors in log files, and on for live -SSLUseStapling off +# SSL Stapling should be off for testing to prevent errors in log files, and on for live. +SSLUseStapling on SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off @@ -76,50 +75,49 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites Header set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline';" - # Disable .htaccess files + # Disable `.htaccess` files. AllowOverride none - # Disable unneeded options + # Disable unneeded options. Options none - # Allow access to www/ + # Allow access to `www/`. Require all granted - # Pass HTTP Authorization headers to PHP-FPM + # Pass HTTP Authorization headers to PHP-FPM. CGIPassAuth on AddType application/x-mobi8-ebook .azw3 - # We explicitly set the content-type for items in the /vocab/ directory, because Apache doesn't set it for us, - # and we need a content-type header when using the "nosniff" header. See https://bugzilla.mozilla.org/show_bug.cgi?id=1547076 + # We explicitly set the content-type for items in the `/vocab/` directory, because Apache doesn't set it for us, and we need a `Content-Type` header when using the `Nosniff` header. See . Header set Content-Type "text/plain" - # Enable HTTP CORS so that browser-based readers like Readium can access opds and ebooks - # Allow fonts for newsletter emails - # See https://github.com/standardebooks/tools/issues/2 + # Enable HTTP CORS so that browser-based readers like Readium can access OPDS and ebooks. + # Allow fonts for newsletter emails. + # See . Header set Access-Control-Allow-Origin "*" - # We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS + # We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS. Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';" - # Remove www from requests + # Remove `www.` from requests. RewriteCond %{HTTP_HOST} ^www\.(.+) [NC] RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L] # PHP-FPM configuration - # See https://serverfault.com/questions/450628/apache-2-4-php-fpm-proxypassmatch/510784 + # See . - # Required for FPM to receive POST data sent with Transfer-Encoding: chunked + # Required for FPM to receive POST data sent with `Transfer-Encoding: chunked`. SetEnv proxy-sendcl 1 - # Forward all PHP requests to the php-fpm pool for this domain. + # Forward all PHP requests to the PHP-FPM pool for this domain. SetHandler "proxy:unix:///run/php/${domain}.sock|fcgi://${domain}" Header set Cache-Control "no-store" @@ -140,47 +138,45 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites RewriteCond %{HTTP_USER_AGENT} ChatGPT-User RewriteRule ^ - [L,R=429] - # In RewriteCond, RewriteRule gets evaluated BEFORE RewriteCond, so $1 refers to the first - # match in RewriteRule - # Rewrite POST /some/url -> POST /some/url/post.php + # In `RewriteCond`, `RewriteRule` gets evaluated *before `RewriteCond`, so `$1` refers to the first match in `RewriteRule`. + # Rewrite POST `/some/url` -> POST `/some/url/post.php`. RewriteCond expr "tolower(%{REQUEST_METHOD}) =~ /^(post|delete|put)$/" RewriteCond %{DOCUMENT_ROOT}/$1/%1.php -f RewriteRule ^([^\.]+)$ $1/%1.php [L] - # In case of 404, serve the 404 page specified by ErrorDocument, not the default FPM error page. - # Note that we can't use `ProxyErrorOverride on` because that catches ALL 4xx and 5xx HTTP headers - # and serves the default Apache page for them. + # In case of 404, serve the 404 page specified by `ErrorDocument`, not the default FPM error page. + # Note that we can't use `ProxyErrorOverride on` because that catches *all* 4xx and 5xx HTTP headers and serves the default Apache page for them. RewriteCond %{REQUEST_FILENAME} \.php$ RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f RewriteRule (.*) - [H=text/html] - # Received: /filename.php and /filename.php exists in filesystem; Result: 301 redirect to /filename and restart request + # Received `/filename.php` and `/filename.php` exists in filesystem -> 301 redirect to `/filename` and restart request. RewriteCond %{REQUEST_FILENAME} \.php$ RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -f RewriteRule ^/(.+)\.php$ /$1 [R=301,L] - # Received: /filename and /filename.php exists in filesystem; Result: change /filename to /filename.php and continue processing + # Received `/filename` and `/filename.php` exists in filesystem -> change `/filename` to `/filename.php` and continue request. RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-d RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI}.php -f RewriteRule ^(.+)$ $1.php [QSA] # End PHP-FPM configuration - # Received: /filename and /filename.xml exists in filesystem; Result: rewrite to /filename.xml + # Received: `/filename` and `/filename.xml` exists in filesystem -> rewrite to `/filename.xml` and continue request. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.xml -f RewriteRule (.*) $1.xml - # Remove trailing slashes + # Remove trailing slashes. RewriteRule ^/(.+?)/$ /$1 [R=301,L] - # Redirect ToC of XHTML representation of books + # Redirect ToC of XHTML representation of books. RewriteRule ^/ebooks/(.+?)/text$ /ebooks/$1/toc.xhtml [L] - # Received: /filename and /filename.xhtml exists in filesystem; Result: rewrite to /filename.xhtml + # Received: `/filename` and `/filename.xhtml` exists in filesystem -> rewrite to `/filename.xhtml` and continue request. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.xhtml -f RewriteRule (.*) $1.xhtml - # Redirect index pages + # Redirect index pages. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.php -f RewriteRule (.*) $1/index.php @@ -189,7 +185,7 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.xml -f RewriteRule (.*) $1/index.xml - # Remove newline characters inserted by accident in some email clients + # Remove newline characters inserted by accident in some email clients. RewriteRule ^(.*)\r\n[\ ]?(.*)$ $1$2 [R=301,N] RewriteRule ^(.*)/r/n[\ ]?(.*)$ $1$2 [R=301,N] RewriteRule ^(.*)/[rn]$ $1 [R=301,N] @@ -203,24 +199,24 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites Include ${conf_rewrite_root}/users.conf Include ${conf_rewrite_root}/projects.conf - # Specific config for /ebooks///downloads + # `XSendFile` configuration for `/ebooks///downloads`. - # Both directives are required + # Both directives are required. XSendFile on XSendFilePath ${web_root}/www/ebooks - # Specific config for /bulk-downloads + # `XSendFile` configuration for `/bulk-downloads`. - # Both directives are required + # Both directives are required. XSendFile on XSendFilePath ${web_root}/www/bulk-downloads - # Specific config for /feeds + # `XSendFile` configuration for `/feeds`. - # This must be defined at the top level /feeds/ directory - # Both directives are required + # This must be defined at the top level `/feeds/` directory. + # Both directives are required. XSendFile on XSendFilePath ${web_root}/www/feeds