Here's one simple way to do it:
RewriteCond %{THE_REQUEST} !HTTP/
RewriteRule .* - [R=451,L]
RewriteCond %{THE_REQUEST} HTTP/1\.0
RewriteRule .* - [R=451,L]
HTTP 0.9 requests are in the format GET /
without any kind of HTTP/XX version indicator, so the first rule will catch them. I've made the rule case sensitive so it will also catch clients who don't capitalize the "HTTP" properly, which shouldn't be a problem for legitimate clients; you can make it case-insensitive if you want but you'd probably want to make the second rule case-insensitive as well so HTTP1.0 traffic can't sneak by as "http/1.0" or similar.
You'll have to decide what kind of response code you want to send back. In this example, I've used R=451
to send back a 451 Unavailable For Legal Reasons
so I can spot these easily in the logs as Apache should never generate that error on its own. (I tried using 418 I'm a teapot
but Apache doesn't currently allow it).
For simplicity, instead of using an R=
, you can simply use G
for 410 Gone
or F
for 403 Forbidden
:
RewriteCond %{THE_REQUEST} !HTTP/
RewriteRule .* - [G,L]
RewriteCond %{THE_REQUEST} HTTP/1\.0
RewriteRule .* - [F,L]
Caveats:
You will still see the requests in your log but you should see the appropriate response code.
If you use custom error pages, you may need additional RewriteCond
statements so that the redirect doesn't trigger again when it tries to load the error page.
Other redirects could potentially get invoked before these redirects. For example, if you put these redirects in global configuration, but also have an HTTP-to-HTTPS redirect in vhost configuration, the latter might get executed first.