.htaccess - redirect favicon - apache

How do I redirect all requests for favicon.ico in root directory or any subdirectory to /images/favicon.ico

Try this rule:
RewriteEngine on
RewriteRule ^favicon\.ico$ /images/favicon.ico [L]
Edit    And for favicon.ico with arbitrary path segment depth:
RewriteCond $0 !=images/favicon.ico
RewriteRule ^([^/]+/)*favicon\.ico$ /images/favicon.ico [L]

For a favicon at www.mysite.com/images/favicon.ico
the most robust method would be:
RewriteCond %{REQUEST_URI} !^/images/favicon\.ico$ [NC]
RewriteCond %{HTTP_HOST} (.+)
RewriteRule ^(.*)favicon\.(ico|gif|png|jpe?g)$ http://%1/images/favicon.ico [R=301,L,NC]
Explanation:
RewriteCond %{REQUEST_URI} !^/images/favicon\.ico [NC] :
- ensures that the redirect rule does NOT apply if the correct URI is requested (eg a 301 redirect will write the correct favicon URI to browser cache - and this line avoids processing the rule if the browser requests the correct URI)
- [NC] means it's not case sensitive
RewriteCond %{HTTP_HOST} (.+) :
- retrieves the http host name - to avoid hard coding the hostname into the RewriteRule
- this means you can copy your .htaccess file between local/test server and production server without problems (or the need to re-hardcode your new site base url into your RewriteRule)
RewriteRule ^(.*)favicon\.(ico|gif|png|jpe?g)$ http://%1/images/favicon.ico [R=301, L] :
- ^ is the start of the regex
- (.*) is a wildcard group - which means that there can be zero or any number of characters before the word favicon in the URI (ie this is the part that allows root directory or any subdirectories to be included in the URI match)
- \.(ico|gif|png|jpe?g) checks that the URI extension matches any of .ico, .gif, .png, .jpg, .jpeg
- $ is the end of the regex
- http://%1/images/favicon.ico is the redirect url - and it injects the hostname we retrieved in the previous RewriteCond. Note that the %1 is a called a RewriteCond backreference this means it is the last RewriteCond that has been met. (eg %2 would be the 2nd-last RewriteCond that to have been met)
- R=301 means it's a permanent redirect - which stores the redirect in the browser cache. Be careful when testing - you'll need to delete browser cache between code changes or the redirect won't update. Probably leave this out until you know the rule works.
- L means its the last redirect to be followed in this .htaccess file - you won't need this to get the rule working since line 1 won't be met once the browser is directed to the correct url. Without the either line 1 or L the RewriteRule will result in a permanent loop (since the redirect URL will keep satisfying the RewriteRule conditions). However, it's a good idea to add the L anyway if you have other rules following the favicon rules - since on a favicon.ico request, you can (probably) ignore any following rules.
You can test .htaccess rules at http://htaccess.mwl.be/
Final Note:
- be careful that you don't have any other RewriteRule in an .htaccess file located in any of your sub-directories.
- eg if you put this answer in your www.mysite.com/ root folder .htaccess file, a RewriteRule (.*) xxx type rule in your www.mysite.com/images/ folder can mess with the results.

RewriteEngine on
RewriteRule ^(.*)favicon\.ico /images/favicon.ico [L]

I know the question is tagged .htaccessbut, why not use a symlink?
ln -s images/favicon.ico favicon.ico

This quick rewrite should do the trick:
RewriteRule ^(.*)favicon.ico /images/favicon.ico

Related

In Apache how to do an external redirect to the slashless version of a URL with a subfolder .htaccess file

On Apache 2.4 I have an .htaccess (in a subfolder) which rewrites slashless requests inside that folder to appropriate index files:
DirectorySlash Off
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule (.*) $1/index.html [L]
This works for the slashless version exactly as expected. Now I want to redirect the slashed version externally to the slashless version. I tried adding the lines:
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} /$
RewriteRule ^(.*)/ $1 [R=302,L]
However this does not work: The redirect is issued, however it does not go to the slashless URL, but to a URL with a system specific part injected.
So, for a sample URL http://example.com/path/to/dir/ the redirected URL looks like this http://example.com/fs9e/username/sub/public/path/to/dir instead of just http://example.com/path/to/dir.
How can I fix this? Many thanks for any pointers!
PS: The real case is a little bit more complicated because I do a subdomain-to-folder rewrite in the root .htacces, but I assume this is not relevant here.
RewriteRule ^(.*)/ $1 [R=302,L]
You are missing the slash prefix (/) on the substitution string (2nd argument) - to make the substitution root-relative. Or rather, /subfolder/ (since this .htaccess file is located in a subfolder). Since this is a relative substitution string (not starting with a slash or scheme+hostname), the directory-prefix*1 (which I assume is /fs9e/username/sub/public/path/) is added back (by default*2), resulting in a malformed redirect. (This is correct for internal rewrites, but not external redirects.)
It should be like this:
RewriteRule ^(.*)/$ /subfolder/$1 [R=302,L]
Note you were also missing the end-of-string anchor ($) on the RewriteRule pattern. (This also negates the need for the preceding condition that checks that REQUEST_URI ends in a slash.)
Note also that this "redirect" should go before the earlier "rewrite".
*1 The directory-prefix is the absolute filesystem path of the location of the .htaccess file.
*2 The alternative is to set a RewriteBase /subfolder - but that then affects all relative substitutions. You could also use an environment variable to apply a specific prefix only to some rules.

Apache htaccess rewrite root and all root folders to subfolder without redirecting

Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
RewriteRule ^$ /subdir/ [L,NC]
I want to rewrite the root domain to subfolder without changing the URL in the browser. The above code works just for the root domain but not any folders and files.
For example, I have https://example.com/ and https://example.com/subdir/.
With the above code in .htaccess file, when I go to https://example.com/ I see the contents of https://example.com/subdir/ which is good.
But when I go to https://example.com/test.txt I should see https://example.com/subdir/test.txt but I get The requested URL was not found on this server.
Same happens when I go to https://example.com/abc expecting to see contents of https://example.com/subdir/abc
Any idea?
RewriteRule ^$ /subdir/ [L,NC]
Change this to read:
RewriteRule !^subdir/ subdir%{REQUEST_URI} [L]
Any request that does not start /subdir/ is internally rewritten to /subdir/<url>. The REQUEST_URI server variable contains the full URL-path (including the slash prefix).
I removed the slash prefix from the substitution string since you have defined a RewriteBase /. (Although neither are strictly necessary here.)
UPDATE:
...when I go to example.com/s I am being redirected to example.com/subdir/s/
s is a subfolder within subdir, does that make any difference?
Ah yes, if /s is a subdirectory then mod_dir will append the trailing slash (to "fix" the URL) with an external 301 redirect. This redirect occurs after the URL has been rewritten to /subdir/s - thus exposing the /subdir subdirectory.
To handle this situation we can add another rule (a redirect) before the existing rewrite that first checks whether the request would map to a directory within the /subdir subdirectory and append a slash if it is omitted (before mod_dir would append the slash to the rewritten URL).
For example:
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/subdir%{REQUEST_URI} -d
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/ [R=301,L]
This states... for any request that:
!\.\w{2,4}$ - does not contain (what looks like) a file extension of between 2 and 4 characters (assuming your directories aren't named this way)
!/$ - and does not currently end in a slash.
-d - and exists as a physical directory in the /subdir subdirectory.
THEN redirect to append the trailing slash on the original request
Whilst this probably should be a 301 (permanent) redirect, you should first test with a 302 (temporary) redirect to avoid potential caching issues.
You will need to clear your browser cache before testing, since the erroneous 301 redirect from /s to /subdir/s/ will have been cached by the browser.
A potential optimisation is to remove the filesystem check and simply assume that any request that does not contain a file extension should map to a directory. (But this depends on whether you are handling these URLs in any other way.)
Summary
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
# If the requested URL exists as a directory in "/subdir" then append a slash
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/subdir%{REQUEST_URI} -d
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/ [R=301,L]
# Rewrite everything to "/subdir"
RewriteRule !^subdir/ subdir%{REQUEST_URI} [L]

Apache rewrite: How to detect & do 301 trailing slash-redirect on my own?

Short version:
I got a request (no trailing slash)
mydomain.com/slides/sessionOne
How can I figure out in a RewriteCond if '_slides/sessionOne' exists and is a directory? If so, append a trailing / (but do not prepend a _) and redirect [R=301].
Long version:
I have a fairly empty webroot:
.htaccess
_slides (dir)
_site (dir)
and a .htaccess that almost does what I want:
RewriteEngine On
RewriteBase /
# directly accessing an _underscore-Folder? – Forbid!
RewriteRule ^_ - [R=403,END]
# AAA
RewriteRule ^slides/(.+)$ _slides/$1 [END]
# prevent _site prepend before _slides
RewriteCond %{REQUEST_URI} !^/_(site|slides)
RewriteRule ^(.*)$ _site/$1 [END]
any URL under slides/ will find it's stuff in the _slides folder
any other url will go and look inside the _site folder
direct access to both underscore-folders is prevented
Directory-URLs with trailing slash work fine, just like files: For example slides/presentation1/ will internally find _slides/presentation1/index.html w/o any visible URL change, as it should.
My trouble: Directory-URLs without trailing slash:
slides/presentation1 will first get (internal, non-visible) rewritten to _slides/presentation1
since the slash is missing, but there is a directoy of that name, Apache automatically makes a visible 301 redirect, sending me to _slides/presentation1/.
But I do not want to reveal the underscore-Folders, and this (correctly) gets caught by my check.
So, I would need at the “AAA” position is in pseudo-code:
URI has no trailing slash
AND there exists a directory either under _slides oder _site?
(peeking for it)
==> make a 301 redirect!
but no underscores prepended, just a trailing slash attached...
Here's my attempt (at the AAA position), but it's just not working:
# directory w/o trailing slash inside _slides/ ?
# ==> attach slash and 301
RewriteCond %{REQUEST_URI} [^/]$
RewriteCond _slides/%{REQUEST_FILENAME} -d [OR]
RewriteCond _site/%{REQUEST_FILENAME} -d
RewriteRule ^ %{REQUEST_URI}/ [R=301,L]
Toughie, but I found a way:
generate a (server-absolute) path to peek for a valid directory (the -d does not care, if your path has 0,1 or even multiple trailing slashes). For generation I use rewrite rules, that don't rewrite anything (“-”), but store what I need in an env var. Only do that for URLs in question, that is: w/o trailing (→[^/]).
Otherwise the env var remains empty. (one of the two, certainly will. Can't match both.)
for applicable (aka non-empty) Env-Vars, check if they are is a directory, if so, append trailing slash, do a 301. (to make the slash-append visible. Like any webservers does..., just under tougher circumstances...).
if there was no 301 (resp. that run happened before), redirect as described in the question.
Code:
RewriteEngine On
RewriteBase /
# already on _underscore-Folder? – Forbid!
RewriteRule ^_ - [R=404,L,END]
# at most one of the two will become valid
RewriteRule ^(slides/.+[^/])$ - [E=slidesPeek:%{DOCUMENT_ROOT}_$1]
RewriteRule ^(?!slides/)(.*[^/])$ - [E=sitePeek:%{DOCUMENT_ROOT}_site/$1]
RewriteCond %{ENV:slidesPeek} !^$
RewriteCond %{ENV:slidesPeek} -d
RewriteRule ^.*$ $0/ [R=301,L,END]
RewriteCond %{ENV:sitePeek} !^$
RewriteCond %{ENV:sitePeek} -d
RewriteRule ^.*$ $0/ [R=301,L,END]
RewriteRule ^slides/(.+)$ _slides/$1 [L,END]
RewriteCond %{REQUEST_URI} !^/_(site|slides)
RewriteRule ^(.*)$ _site/$1 [END]
Bonus 8-) Useful for testing and debugging:
RewriteRule ^(?!DEBUG)\w+$ /DEBUG?%{DOCUMENT_ROOT} [R=301,END]
Caveat:
Flag [L] means: stop for the rest of this .htacess-file (but possible do additional rounds from start. On 301 redirects and on internal rewrites)
Flag [END] means: No additional rounds... (except for 301, which inevitably starts the whole thing). [END] does NOT imply [L]. Without [L], rules that follow would still be applied, just no additional rounds
Something, that one won't notice on more trivial cases.
Just for reference: (mind all the slashes)
%{DOCUMENT_ROOT}
/is/htdocs/user12345678/www.mydomain.de/
%{REQUEST_FILENAME}
/is/htdocs/user12345678/www.mydomain.de/abc
%{REQUEST_URI}
uri=/abc
Preceeding slashes are a constant pain by the way: RewriteRule get's the URL without initial slash, whereas %{REQUEST_URI} has one...
I honestly no longer understand, why the seconds-last line is needed. But deletion gets me 404s...
Advice:
Browsers notoriously cache your prior 301-redirects (keep sending you there again, without checking.)
Thus either you need to keep cleaning caches all the time or you do your testing from the command line, i.e.
cd someTemporaryFolder
wget http://mywhateverurl.com 2>&1
resp.
wget http://mywhateverurl.com 2>&1 | grep Location:

Images don't load after htaccess redirect

I wanted to redirect all IPs to a specific page except my IP. and I successfully did that, but if that page has some pictures they won't ever load. Tried more than one solution, but nothing works.
How I redirect them using .htacess file:
Options +FollowSymLinks
RewriteEngine on
RewriteRule (?:^|/)(css|js|img)/(.+)$ /$1/$2 [NC,QSA,L]
RewriteCond %{HTTP:X-FORWARDED-FOR} !^22\.22\.22\.22
RewriteCond %{REQUEST_URI} !/test.php$ [NC]
RewriteRule .* /test.php [R=302,L]
Images (and CSS and Javascript) don't load, because the first rule causes a rewrite loop. If you just want to serve requests to subfolders css, js or img without modification, you can exit the rule chain by using - as the target, see RewriteRule
- (dash)
A dash indicates that no substitution should be performed (the existing path is passed through untouched). This is used when a flag (see below) needs to be applied without changing the path.
RewriteRule ^(?:css|js|img)/ - [NC,L]

htaccess - Redirect to subfolder without changing browser URL

I've a domain that contains a subfolder with the web app structure. I added a .htaccess on my root domain to point the public folder on my subfolder web app. It works fine, but when I type www.example.com the browser URL changes to www.example.com/subfolder/public, but I would like that it doesn't change.
This is my .htaccess:
RewriteEngine On
RewriteRule ^.*$ subfolder/public [NC,L]
EDIT
This first .htaccess is used to redirect on subfolder/public, where there is an other .htaccess that makes all the works.
Here the code of the second .htaccess located on www.example.com/subfolder/public/:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Sorry, just realised what is happening. It has nothing to do with the second .htaccess file in the subdirectory, as mentioned in comments.
RewriteRule ^.*$ subfolder/public [NC,L]
Since public is a physical directory on the file system, you need to include a trailing slash when internally rewriting to that directory. Otherwise, mod_dir is going to try to "fix" the URL by appending a slash - that is where the external redirect is coming from. (mod_dir implicitly triggers an external redirect from subfolder/public to subfolder/public/.)
So, try the following instead in your root .htaccess file:
RewriteRule .* subfolder/public/ [L]
The important thing is the trailing slash. The anchors (^ and $) on the RewriteRule pattern are not required, since you are matching everything. And the NC flag is also not required for the same reason.
As always, make sure the browser cache is clear before testing.
UPDATE#1: The single directive above rewrites everything, including static resources, to the directory subfolder/public/ which then relies on the second .htaccess file in the subdirectory to correctly route the request. In order to allow static resources to be rewritten correctly (represented in the HTML as root-relative URL-paths, of the form "/js/myjs.js") then you will need additional directives in order to rewrite these.
For example, to specifically rewrite all .js and .css files to the real location in /subfolder/public/...
# Rewrite static resources
RewriteRule (.+\.(?:js|css))$ subfolder/public/$1 [L]
# Rewrite everything else to the "public" directory
RewriteRule .* subfolder/public/ [L]
UPDATE#2: To make the above more general, and to rewrite any static resource (images, PDFs, .txt, etc...) we can check for the existence of the file before rewriting, something like:
# Rewrite static resources
RewriteCond %{DOCUMENT_ROOT}/subfolder/public/$1 -f
RewriteRule (.+) subfolder/public/$1 [L]
# Rewrite everything else to the "public" directory
RewriteRule .* subfolder/public/ [L]
This will mean that if any .css does not exist it will be passed through to subfolder/public/.