I've just taken on hosting of an ancient site that was converted from asp to static html, consisting of about 6,000 files. However, my server doesn't like the filenames, giving a 404 error. The URLs are all of the form:


where id is always an integer and a is always a string of characters & numbers.

Is there any way I can use htaccess and mod_rewrite to tell it that the question mark is part of the URL rather than signifying a query string?

  • Using the ? to separate arguments from the URI is the default behavior. How do you have apache configured now? And does filename.asp exist in the directory you're shooting for?
    – Jack M.
    Jun 2, 2011 at 19:02
  • Apache is configured pretty much out of the box excerpt for performance changes. But as i've got multiple sites on the server i can't change it server-wide, so I'd be looking to do something via htaccess. Jun 2, 2011 at 20:40

3 Answers 3


You probably already know you are not the first person to have this need :)

# Allow filenames containing '?' to be served by escaping the '?' in the HTTP
# request so it's not interpreted as a query string.
# Apache 2.2: set query string to empty by ending rewritten path with '?'.
# Apache 2.4: use the qsdiscard flag instead
RewriteCond %{QUERY_STRING} !=""
RewriteRule ^/(.*) /$1\%3F%{QUERY_STRING}? [noescape,last,redirect]

The key is the combination of adding a redirect and NE/noescape to ensure apache doesn't escape what we don't want escaped.

The above rule will mean that the entire site under this rewrite will treat ? as part of the filename. If you need to have it match your filename.asp - just add it to the RewriteRule


I would suggest a rewrite that directly serve the file, by escaping the "?" to "\%F3".

To serve files:

RewriteCond %{QUERY_STRING} !=""
RewriteRule ^(.*)$ $1\%3F%{QUERY_STRING}? [L]

Do the same for folders (i.e. serve index.html - adapt index.html to fit your needs)

RewriteCond %{REQUEST_FILENAME} ^.*/$
RewriteCond %{QUERY_STRING} !=""
RewriteRule ^(.*)/$ $1/index.html\%3F%{QUERY_STRING}? [L]

First, we test if the file exists (see next paragraph about this), second we check that we have a query string (otherwise, serve the file as usual), then add the "?" and the original query string and serve it.

I add the "?" at the end, to erase the QueryString (since it is already handled), and to avoid the rule to be applied a second time (ex: if serving a file in a subdirectory). Other solution would be to use the "END" flag (see http://httpd.apache.org/docs/current/en/mod/mod_rewrite.html#rewriterule). According to the same page, and as mentionned by @csharkey and @Gavin C, [qsdiscard] could be added instead in apache 2.4:

RewriteRule ^(.*)/$ $1/index.html\%3F%{QUERY_STRING}? [L,qsdiscard]

Caveat: I didn't test this solution thouroughly, so errors may remains.


I have converted an ancient Joomla site with wget --mirror. In my case all the links went through the index.php file, so all of them are something like site.com/index.php?blabla=haha.

I have resolved the problem by adding an index.php file with the following content:


include 'index.php?' . $_SERVER['QUERY_STRING'];

This way you don't even need the rewrite module. Obviously it performs slightly worse, and maybe it's less elegant, but at least you don't have to convert link/filenames.

Your Answer

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

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