1

I have the same issue as mentioned on Redirect AMP Parameter To Its Permalink, the solution given by Mrwhite solved my problem and everything went fine

# Redirect old "amp" URLs back to permalink (general version)
RewriteCond %{QUERY_STRING} ^(.*&)?(?:no)?amp(?:=[^&]*)?&?(.*)$ [OR]
RewriteCond %{REQUEST_URI} /amp/?$
RewriteRule ^/?(.*?)(/amp/?)?$ /$1?%1%2 [NE,R=301,L]

But then I upgraded my MariaDB and PHP version from php74 to php80, I did yum install and made changes to my .confs (mariaDB,PHP and vhost.conf)

but after restarting the service, htaccess code stop working (well partially). parameter seems still working correctly but /amp/ /amp ended up in redirect loop

Request 
> GET /amp/ HTTP/1.1
> Host: www.example.com
> User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http;//www.google.com/bot.html)
Response 
< HTTP/1.1 301 Moved Permanently
< Date: Wed, 13 Apr 2022 09:46:52 GMT
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 241
< Connection: keep-alive
< Location: https://www.example.com/amp/
< Cache-Control: max-age=0
< Expires: Wed, 13 Apr 2022 09:46:52 GMT
< CF-Cache-Status: DYNAMIC
< Strict-Transport-Security: max-age=31536000; includeSubexamples; preload
< X-Content-Type-Options: nosniff
< Server: cloudflare
< CF-RAY: 6fb346ee4f66984f-SJC
< alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
Request 
> GET /amp/ HTTP/1.1
> Host: www.example.com
> User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Response 
< HTTP/1.1 301 Moved Permanently
< Date: Wed, 13 Apr 2022 09:46:52 GMT
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 241
< Connection: keep-alive
< Location: https://www.example.com/amp/
< Cache-Control: max-age=0
< Expires: Wed, 13 Apr 2022 09:46:52 GMT
< CF-Cache-Status: DYNAMIC
< Strict-Transport-Security: max-age=31536000; includeSubexamples; preload
< X-Content-Type-Options: nosniff
< Server: cloudflare
< CF-RAY: 6fb346efb94c984f-SJC
< alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
Request 
> GET /amp/ HTTP/1.1
> Host: www.example.com
> User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http;//www.google.com/bot.html)
Request failed

It seems during upgrading PHP and MariaDB I made changes to my configuration which causing code above stop working but I'm not quite sure which one

Bellow is My configuration

After yum update

[root@home ~]# httpd -M

Loaded Modules:
 core_module (static)
 so_module (static)
 http_module (static)
 access_compat_module (shared)
 actions_module (shared)
 alias_module (shared)
 allowmethods_module (shared)
 auth_basic_module (shared)
 auth_digest_module (shared)
 authn_anon_module (shared)
 authn_core_module (shared)
 authn_dbd_module (shared)
 authn_dbm_module (shared)
 authn_file_module (shared)
 authn_socache_module (shared)
 authz_core_module (shared)
 authz_dbd_module (shared)
 authz_dbm_module (shared)
 authz_groupfile_module (shared)
 authz_host_module (shared)
 authz_owner_module (shared)
 authz_user_module (shared)
 autoindex_module (shared)
 cache_module (shared)
 cache_disk_module (shared)
 data_module (shared)
 dbd_module (shared)
 deflate_module (shared)
 dir_module (shared)
 dumpio_module (shared)
 echo_module (shared)
 env_module (shared)
 expires_module (shared)
 ext_filter_module (shared)
 filter_module (shared)
 headers_module (shared)
 include_module (shared)
 info_module (shared)
 log_config_module (shared)
 logio_module (shared)
 mime_magic_module (shared)
 mime_module (shared)
 negotiation_module (shared)
 remoteip_module (shared)
 reqtimeout_module (shared)
 rewrite_module (shared)
 setenvif_module (shared)
 slotmem_plain_module (shared)
 slotmem_shm_module (shared)
 socache_dbm_module (shared)
 socache_memcache_module (shared)
 socache_shmcb_module (shared)
 status_module (shared)
 substitute_module (shared)
 suexec_module (shared)
 unique_id_module (shared)
 unixd_module (shared)
 userdir_module (shared)
 version_module (shared)
 vhost_alias_module (shared)
 dav_module (shared)
 dav_fs_module (shared)
 dav_lock_module (shared)
 lua_module (shared)
 mpm_prefork_module (shared)
 proxy_module (shared)
 lbmethod_bybusyness_module (shared)
 lbmethod_byrequests_module (shared)
 lbmethod_bytraffic_module (shared)
 lbmethod_heartbeat_module (shared)
 proxy_ajp_module (shared)
 proxy_balancer_module (shared)
 proxy_connect_module (shared)
 proxy_express_module (shared)
 proxy_fcgi_module (shared)
 proxy_fdpass_module (shared)
 proxy_ftp_module (shared)
 proxy_http_module (shared)
 proxy_scgi_module (shared)
 proxy_wstunnel_module (shared)
 ssl_module (shared)
 systemd_module (shared)
 cgi_module (shared)
 fcgid_module (shared)
 php5_module (shared)

Vhost.conf

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName example.com
    ServerAlias www.example.com

Redirect permanent / https://www.example.com/

</VirtualHost>

<VirtualHost *:443>
    ServerAdmin [email protected]
    ServerName example.com
    ServerAlias www.example.com
    
    DocumentRoot /var/www/html/site1
<IfModule dir_module>
    DirectoryIndex index.php index.htm index.html
</IfModule>

  <Directory /var/www/html/site1>
      Options -Indexes +FollowSymLinks +Includes +ExecCGI
      AllowOverride All
      Require all granted
  </Directory>

<Files xmlrpc.php>
order deny,allow
deny from all
</Files>
  
<IfModule mod_headers.c>
  <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font|css|css|js)$">
    Header set Access-Control-Allow-Origin "*"
  </FilesMatch>
</IfModule>
  
<FilesMatch "\.php$">
 <If "-f %{REQUEST_FILENAME}">
        SetHandler "proxy:fcgi://127.0.0.1:9080"
</If>
</FilesMatch>

 ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
     AddHandler php80-fcgi .php
     Action php80-fcgi /cgi-bin/php80.fcgi
     

Redirect 410 /home-marketing
Redirect 410 /search/
Redirect 410 /entertainment


SSLEngine on
SSLCertificateFile /var/www/123.pem
SSLCertificateKeyFile /var/www/123.key
SSLCACertificateFile /var/www/origin.pem

</VirtualHost>

Htaccess

# BEGIN WP Rocket v3.11.0.1
# Use UTF-8 encoding for anything served text/plain or text/html
AddDefaultCharset UTF-8
# Force UTF-8 for a number of file formats
<IfModule mod_mime.c>
AddCharset UTF-8 .atom .css .js .json .rss .vtt .xml
</IfModule>

# FileETag None is not enough for every server.
<IfModule mod_headers.c>
Header unset ETag
</IfModule>

# Since we’re sending far-future expires, we don’t need ETags for static content.
# developer.yahoo.com/performance/rules.html#etags
FileETag None

<IfModule mod_alias.c>
<FilesMatch "\.(html|htm|rtf|rtx|txt|xsd|xsl|xml)$">
<IfModule mod_headers.c>
Header unset Pragma
Header append Cache-Control "public"
Header unset Last-Modified
</IfModule>
</FilesMatch>

<FilesMatch "\.(css|htc|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
<IfModule mod_headers.c>
Header unset Pragma
Header append Cache-Control "public"
</IfModule>
</FilesMatch>
</IfModule>

<IfModule mod_mime.c>
    AddType image/avif                                  avif
    AddType image/avif-sequence                         avifs
</IfModule>
# Expires headers (for better cache control)
<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault                              "access plus 1 month"
    # cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
    ExpiresByType text/cache-manifest           "access plus 0 seconds"
    # Your document html
    ExpiresByType text/html                     "access plus 0 seconds"
    # Data
    ExpiresByType text/xml                      "access plus 0 seconds"
    ExpiresByType application/xml               "access plus 0 seconds"
    ExpiresByType application/json              "access plus 0 seconds"
    # Feed
    ExpiresByType application/rss+xml           "access plus 1 hour"
    ExpiresByType application/atom+xml          "access plus 1 hour"
    # Favicon (cannot be renamed)
    ExpiresByType image/x-icon                  "access plus 1 week"
    # Media: images, video, audio
    ExpiresByType image/gif                     "access plus 4 months"
    ExpiresByType image/png                     "access plus 4 months"
    ExpiresByType image/jpeg                    "access plus 4 months"
    ExpiresByType image/webp                    "access plus 4 months"
    ExpiresByType video/ogg                     "access plus 4 months"
    ExpiresByType audio/ogg                     "access plus 4 months"
    ExpiresByType video/mp4                     "access plus 4 months"
    ExpiresByType video/webm                    "access plus 4 months"
    ExpiresByType image/avif                    "access plus 4 months"
    ExpiresByType image/avif-sequence           "access plus 4 months"
    # HTC files  (css3pie)
    ExpiresByType text/x-component              "access plus 1 month"
    # Webfonts
    ExpiresByType font/ttf                      "access plus 4 months"
    ExpiresByType font/otf                      "access plus 4 months"
    ExpiresByType font/woff                     "access plus 4 months"
    ExpiresByType font/woff2                    "access plus 4 months"
    ExpiresByType image/svg+xml                 "access plus 4 months"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    # CSS and JavaScript
    ExpiresByType text/css                      "access plus 1 year"
    ExpiresByType application/javascript        "access plus 1 year"
</IfModule>
# Gzip compression
<IfModule mod_deflate.c>
# Active compression
SetOutputFilter DEFLATE
# Force deflate for mangled headers
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
# Don’t compress images and other uncompressible content
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp|pdf)$ no-gzip dont-vary
</IfModule>
</IfModule>

# Compress all output labeled with one of the following MIME-types
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE application/atom+xml \
                                  application/javascript \
                                  application/json \
                                  application/rss+xml \
                                  application/vnd.ms-fontobject \
                                  application/x-font-ttf \
                                  application/xhtml+xml \
                                  application/xml \
                                  font/opentype \
                                  image/svg+xml \
                                  image/x-icon \
                                  text/css \
                                  text/html \
                                  text/plain \
                                  text/x-component \
                                  text/xml
</IfModule>
<IfModule mod_headers.c>
Header append Vary: Accept-Encoding
</IfModule>
</IfModule>

# END WP Rocket

# Redirect old "amp" URLs back to permalink (general version)
RewriteCond %{QUERY_STRING} ^(.*&)?(?:no)?amp(?:=[^&]*)?&?(.*)$ [OR]
RewriteCond %{REQUEST_URI} /amp/?$
RewriteRule ^/?(.*?)(/amp/?)?$ /$1?%1%2 [NE,R=301,L]

# BEGIN WordPress

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

#Redirect Wwww https://www.danielmorell.com/guides/htaccess-seo/redirects/https-www-and-trailing-slash
#### Force https;//WWW and remove trailing / from files ####
## Turn on rewrite engine
#RewriteEngine on

# Remove trailing slash from non-filepath urls
RewriteCond %{REQUEST_URI} /(.+)/$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ https://www.example.com/%1 [R=301,L]

# Include trailing slash on directory 
RewriteCond %{REQUEST_URI} !(.+)/$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)$ https://www.example.com/$1/ [R=301,L]

# Force HTTPS and WWW 
RewriteCond %{HTTP_HOST} !^www\.(.*)$ [OR,NC]
RewriteCond %{https} off  
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

1 Answer 1

0
RewriteRule ^/?(.*?)(/amp/?)?$ /$1?%1%2 [NE,R=301,L]

This is actually a bug in the rule itself (sorry)!

AFAICT this is only an issue with requests for example.com/amp (and /amp/) - in the root - as per your example. A request for /<anything>/amp would be OK (/amp is stripped).

This was not actually one of the 28 test cases on the original question, where /amp always follows a non-empty URL-path (ie. not in the root), so the criteria for that question are arguably still satisfied. (Although this is still obviously a bug.)

Although why you are seemingly only seeing this issue after a server upgrade is a bit of a mystery. (Unless this particular request wasn't actually tested earlier?!)

The reason for the redirect loop when requesting just /amp or /amp/ is that the second capturing group (/amp/?)? fails to match since there is no slash prefix (as there is for /<something>/amp) and since this is optional (because amp might be present in the query string instead) amp (or amp/) is matched by the first capturing group instead (like a regular URL-path), which propagates to the redirected URL and amp (or amp/) is not removed.

I believe this can be fixed by simply making the second slash (ie. the first slash in the second capturing group (/amp/?)?) optional also. ie. (/?amp/?)?. For example:

:
RewriteRule ^/?(.*?)(/?amp/?)?$ /$1?%1%2 [NE,R=301,L]

So, the complete rule becomes:

# Redirect old "amp" URLs back to permalink (general version)
RewriteCond %{QUERY_STRING} ^(.*&)?(?:no)?amp(?:=[^&]*)?&?(.*)$ [OR]
RewriteCond %{REQUEST_URI} /amp/?$
RewriteRule ^/?(.*?)(/?amp/?)?$ /$1?%1%2 [NE,R=301,L]

Aside:

# Remove trailing slash from non-filepath urls
RewriteCond %{REQUEST_URI} /(.+)/$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ https://www.example.com/%1 [R=301,L]

# Include trailing slash on directory 
RewriteCond %{REQUEST_URI} !(.+)/$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)$ https://www.example.com/$1/ [R=301,L]

# Force HTTPS and WWW 
RewriteCond %{HTTP_HOST} !^www\.(.*)$ [OR,NC]
RewriteCond %{https} off  
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

These 3 rules are in the wrong place. You currently have these at the very end of your .htaccess file. However, they need to go before the WordPress front-controller, ie. before the # BEGIN WordPress comment marker.

By placing them at the end (ie. after the WP front-controller) they are simply never going to be processed for most requests (except the 2nd rule).

The 2nd rule is not strictly required here, since mod_dir will append the trailing slash to directories as required (I can't see that this behaviour has been disabled in the config you've posted).

3
  • I have no idea why the loop occurs after PHP upgrade..but yea before the upgrade ( using PHP-fpm 74 and stock centos 7) the rule works as expected...only after upgrading I notice URL errors example.com/amp.. I thought it was because of the changes that I made on the server. conf...so my server. conf is fine?
    – Anton Nb
    Apr 14, 2022 at 13:19
  • @AntonNb "I notice URL errors" - in your logs? Is it possible users were previously seeing a (server-side?) cached response? And a server upgrade cleared that cache?! No URL "errors", but no redirect either. (?) On a glance through your conf - it looks fine - other than the issues I mentioned above from your .htaccess file.
    – MrWhite
    Apr 14, 2022 at 16:08
  • no, i rarely log into my server...URL errors were reported by WordPress plugins called Broken Link Checker https://wordpress.org/plugins/broken-link-checker/
    – Anton Nb
    Apr 15, 2022 at 11:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.