Apache Rewrite Rule – How to Return 301 Redirect Instead of 302

apache-2.4Apache2httpdmod-rewriterewrite

I have two different examples of where Apache Httpd 2.4 on Centos7 is configured to perform redirects with the R=301 flag, but they are actually returning 302 redirects. One is an extremely simple case, just redirecting http to https. Here is the extent of the rewrite rules:

<VirtualHost ...>
  ... other content ...
  RewriteEngine On
  RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
  RewriteCond %{HTTP:X-Forwarded-Proto} !https
  RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>

Why is this returning a 302 redirect instead of 301?

# apachectl -S
VirtualHost configuration:
wildcard NameVirtualHosts and _default_ servers:
*:80                   example.com (/etc/httpd/sites- 
enabled/example.com.conf:5)
*:443                  example.com (/etc/httpd/sites- 
enabled/example.com.conf:23)
Syntax OK

Best Answer

Your problem is that you are not using the appropriate hostname for curl. The rewrite rule is triggered on condition of matching hostname example.com. If you are just using curl http://localhost then httpd gets the hostname "localhost" and the rule does not match. Instead use the curl command with a --proxy argument pointing at localhost (be sure to specify the port number!) and the url argument matching the expected host name. Like this:

curl --proxy localhost:80 http://example.com