site 5x faster via mod_rewrite, but CSS images are broken - css

I am using .htaccess to accelerate a site with the following redirects:
request for http://example.com/images/name.jpg routed to http://i.example.com/name.jpg
request for http://example.com/css/name.css routed to http://c.example.com/name.css
From listening to the Stack Overflow podcast, I learned that this could make a site faster, since the browser can download more files simultaneously (apparently two streams per domain, although this is unconfirmed).
Indeed, the difference is dramatic; the page loads about five times as fast!
I have not touched the original folders and images -- I am just using mod_rewrite to change the addresses from example.com/images/ to i.example.com/:
rewritecond %{HTTP_HOST} !^i\.example\.com [NC]
rewriterule ^images/([^/]+)$ http://i.example.com/$1 [L]
rewritecond %{HTTP_HOST} !^c\.example\.com [NC]
rewriterule ^css/([^/]+)$ http://c.example.com/$1 [L]
The problem I have is that this technique works perfectly for image tags included in html, but doesn't work for images included via stylesheets:
img src=/images/logo.jpg works perfectly
background:url(/images/logo.jpg); does not work
The server error log contains the following entry:
File does not exist: /var/www/html/css/images, referer: http://example.com/page.html
This seems to imply that the rewrite rule is being applied incorrectly.
The stylesheets work if I use:
background:url(http://i.example.com/logo.jpg);
However, in order to avoid rewriting all the style sheets, I'd like to know: why doesn't url rewriting apply to stylesheets the way it does to html img tags.
[update1] This problem exists in Safari 4 Beta, Firefox 3.0.3, and Chrome, but the page works perfectly in IE6.
[update2] Adding [L,R=301] and [L,R=302] did not help.
[update3] I tried the following based on Gumbo's suggestion below:
Redirect externally if path doesn’t match host name:
rewritecond %{HTTP_HOST} !^i\.domain\.com$
rewriterule ^images/([^/]+)$ http://i.domain.com/$1 [L,R=301]
rewritecond %{HTTP_HOST} !^c\.domain\.com$
rewriterule ^css/([^/]+)$ http://c.domain.com/$1 [L,R=301]
Redirect internally; if there's an unnecessary folder name remove it (see server error above):
rewritecond %{HTTP_HOST} ^i\.domain\.com$
rewriterule ^images/([^/]+)$ $1 [L]
rewritecond %{HTTP_HOST} ^c\.domain\.com$
rewriterule ^css/([^/]+)$ $1 [L]
It still didn't work. Bizarrely, the server error is:
File does not exist: /var/www/html/css/var, referer: http://domain.com/page.html

I was able to resolve this by not trying to incorporate directories into the subdomains:
request for domain.com/images/ routed to i.domain.com/images/
request for domain.com/css/ routed to c.domain.com/css/
It works perfectly and is still extremely fast.
There seems to be a bug in modern browsers where a css request that is redirected will apply only the new domain, leaving the original directories as part of the request:
If a css image at url(domain.com/images/name.jpg) is redirected to i.domain.com/name.jpg, the browser will mistakenly request i.domain.com/images/name.jpg.

I found a way to solve this problem if all host names use the same virtual host:
# redirect externally if path doesn’t match host name
RewriteCond %{HTTP_HOST} !^i\.example\.com$
RewriteRule ^images/([^/]+)$ http://i.example.com/$1 [L,R=301]
RewriteCond %{HTTP_HOST} !^c\.example\.com$
RewriteRule ^css/([^/]+)$ http://c.example.com/$1 [L,R=301]
# redirect internally to the file
RewriteCond %{HTTP_HOST} ^i\.example\.com$
RewriteRule !^images/ images%{REQUEST_URI} [L]
RewriteCond %{HTTP_HOST} ^c\.example\.com$
RewriteRule !^css/ css%{REQUEST_URI} [L]
This will do the following:
http://example.com/css/foo externally to http://c.example.com/foo
http://c.example.com/foo internally to /css/foo
http://example.com/images/bar externally to http://i.example.com/bar
http://i.example.com/bar internally to /images/bar
As well as correcting mismatching paths and host names:
http://i.example.com/css/foo externally to http://c.example.com/foo
http://c.example.com/images/bar externally to http://i.example.com/bar
A mismatch occurs when the requested stylesheet http://example.com/css/foo is redirected to http://c.example.com/foo and an image URI reference like /images/bar inside the stylesheet is resolved from this new base URI and thus leading to http://c.example.com/images/bar instead of the initial http://example.com/images/bar.

Related

htaccess restrict access to ALL pages but referrer

I managed to restrict access to my site using the .htaccess directives below. It works pretty well BUT I found that people other than referrer success to access direct page like https://example.com/**pages**/ and from there can go back to home. How can I restrict to all site but the referrer (so all tree from my root URL).
# Serve everyone from specific-domain (and internal requests)
RewriteCond %{HTTP_REFERER} ^https?://www\.your-domain\.com/ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.specific-domain\.com/
RewriteRule ^ - [L]
# everybody else receives a forbidden
RewriteRule ^ - [F]
From discussion on your other question, it seems you have been putting these directives in the wrong place. It is a WordPress site and the directives have been placed after the WordPress front-controller, ie. after the # BEGIN WordPress ... # END WordPress code block.
This is actually a very common mistake. But order matters.
By placing them at the end of the file they are simply never going to be processed for requests to example.com/<wordpress-url>, because the request has already been routed to the WordPress front-controller (index.php).
These blocking directives need to go at the very top of the .htaccess file. Importantly they must go before the # BEGIN WordPress section.
You should NOT place these directives inside the WordPress code block since WordPress maintains this section and will likely overwrite any custom directives you place here.
You do not need to repeat the RewriteEngine On directive (which appears later in the file - the order of this directive does not matter). In fact, if there are multiple RewriteEngine directives then the last directive wins and controls the entire file/context.
UPDATE#1:
is there a way to exclude a single page from the directives so that this page can still be available even from non referrer - it would be a login page
Yes, you can add an additional condition to the first block that checks for this URL. For example:
# Serve everyone from specific-domain (and internal requests)
RewriteCond %{REQUEST_URI] ^/login$ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.your-domain\.com/ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.specific-domain\.com/
RewriteRule ^ - [L]
# Everybody else receives a forbidden
RewriteRule ^ - [F]
UPDATE#2:
However, since this is a WordPress site, you still need processing to continue to the front-controller (the # BEGIN WordPress section later in the file) in order to route the URLs. This would explain why you are seeing 404s for /<page> and other WordPress URLs despite the Referer presumably being set correctly.
To resolve this, change the [L] flag in the first RewriteRule to [S=1] (skip 1 rule), so instead of stopping further processing (the effect of the L / last flag), it simply skips the following rule that blocks access for everyone else. And continues on to the WordPress front-controller.
For example:
:
RewriteRule ^ - [S=1]
# Everybody else receives a forbidden
RewriteRule ^ - [F]
Alternatively, you could reverse the logic...
# Block everyone from "other" domains except for specific URLs
RewriteCond %{REQUEST_URI] !^/login$
RewriteCond %{HTTP_REFERER} !^https?://www\.your-domain\.com/
RewriteCond %{HTTP_REFERER} !^https?://www\.specific-domain\.com/
RewriteRule ^ - [F]
# BEGIN WordPress
:

Can you have a conditional in the htaccess file

Been looking around the web to add a production rule in the .htaccess file. I have a wordpress website; one for production and the other, staging.
When a file is uploaded, it goes to AWS (s3). I need to prevent this behaviour for staging.
The code that sets the asset path is, in the .htaccess file:
RewriteRule ^wp-content/uploads/(.*)$ https://s3-eu-west-1.amazonaws.com/<BUCKET-NAME>/wp-content/uploads/$1 [R=301,L]
I cant seem to find an "if statement" or some sort of condition to use. Honestly, I think this is not possible. Is it?
I only need to run that code for production and not staging. Staging url is different from production.
Updated
Whenever I use below, my website crashes:
<If "-z req('Host') == 'www.<PRODUCTION>.com/'">
RewriteRule ^wp-content/uploads/(.*)$ https://s3-eu-west-1.amazonaws.com/<BUCKET-NAME>/wp-content/uploads/$1 [R=301,L]
</If>
If directive works on Apache 2.4 and newer versions. On lower versions you can use RewriteCond directive to conditionally rewrite urls.
You can use something like this
RewriteEngine on
#if host == "www.production.com"
RewriteCond %{HTTP_HOST} ^www.production.com$ [NC]
# execute the rule
RewriteRule ^wp-content/uploads/(.*)$ https: //s3-eu-west-1.amazonaws.com/<BUCKET-NAME>/wp-content/uploads/$1 [R=301,L]

Domain address- misunderstanding in WordPress

I don't understand why this Url:
www.hortadascanas.com
and this Url:
http://hortadascanas.com
are not pointing to the same page. If you look the content, you can see that icons don't show up at the 2nd adress...Actually It seems to me that the 2nd Url links to an older version of the page.
I thought the "www" was a shortcut of "/public_html".
If I try with this address http://hortadascanas.com/location it is redirected to http://www.hortadascanas.com/location but the home page is not redirected.
What is happening ?
EDIT
This is what I have in my .htaccess file:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
I guess I have to remove some lines because the site crashes if I add the lines you gave me....I have redirections loops...
EDIT 2
Should I delete this red line and recreate one pointing to the alias www.hortadascanas.com ?
This can be done by adding the following lines at the beginning of the .htaccess file in your public_html folder:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.hortadascanas.com [NC]
RewriteRule ^(.*)$ http://hortadascanas.com/$1 [L,R=301]
if you want to redirect both HTTP and HTTPS non-www Urls to www, you can combine rules as follows:
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.yourdomain.com/$1 [L,R=301]
For more information please read following :
https://www.siteground.com/kb/how_to_redirect_www_urls_to_nonwww/
Edit
In your case its because of CNAME in your cloudflare,please check complete guide for this,
https://help.ghost.org/hc/en-us/articles/223210747-Root-Domain-Setup-Using-CloudFlare
www.hortadascanas.com and hortadascanas.com are simply different hostnames.
They don't have identical DNS resolution:
[ ~ ]
[ user ][ user#workstation.local ] % host hortadascanas.com
hortadascanas.com has address 69.195.124.135
hortadascanas.com mail is handled by 0 mail.hortadascanas.com.
[ ~ ]
[ user ][ user#workstation.local ] % host www.hortadascanas.com
www.hortadascanas.com has address 104.27.134.235
www.hortadascanas.com has address 104.27.135.235
www.hortadascanas.com has IPv6 address 2400:cb00:2048:1::681b:86eb
www.hortadascanas.com has IPv6 address 2400:cb00:2048:1::681b:87eb
You end up talking to two different computers depending on which hostname you use.
Running the IP addresses through whois we can see that www.hortadascanas.com is handled by Cloudflare, who provide a CDN and caching service.
Actually It seems to me that the 2nd Url links to an older version of the page.
Presumably Cloudflare is loading the data from 69.195.124.135 and caching it … so it is an older version of the page.
Even if the two hostnames' DNS resolved to the same computer, you could still get different content. Name based virtual hosting allows multiple websites to share a single IP address. The Hostname is included in the HTTP request header so the server can determine which site to return.

Using .htaccess to prevent a DDOS attack not working with Permalinks

We have become the victim of a vicious DDOS attack on a WordPress site.
Thankfully, they should be easily removed as they are GET requests with the string ?ptrxcz appended to the end of the URL.
With this in mind we have set up rules to give 403 permission error pages to requests that fulfill this using .htacess. The trouble is these don't appear to work with permalinks installed also.
Here is my full .htaccess file as it is.
RewriteEngine On
RewriteCond %{QUERY_STRING} .*ptrxcz.*
RewriteRule (.*) - [F]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
The beginning part is redirecting users with ptrxcz to the 403 page. This works perfectly if I remove the WordPress rules underneath it, but with them included it just never works.
Frustratingly using a negative regex with the QUERY_STRING search works in reverse correctly (blocking everything except request with the query string, as so:
RewriteCond %{QUERY_STRING} !.*ptrxcz.*
(Note the added !)
Does anyone have any idea:
Why it doesnt work with permalinks
How I can make it work with permalinks
Why a negative regex on the query string works but not a positive one.
I had the same problem, but it was severe enough that I brought up a small web server to act as a front end and filter out these requests. The relevant iptables rule is:
iptables -A INPUT -p tcp --dport 80 -m string --to 70 --algo bm --string 'ptrxcz_' -j DROP
It instructs the system to examine up to the first 70 characters of the request and if it finds 'ptrxcz_ ', to silently drop the request. I tried returning an error message, but the bandwidth consumed by the error code was not worth it considering there would never be a user on the other end of the connection to read the error.
I created a blog post describing the steps I took:
http://web.htcomp.net/?pageid=85&blogid=2
Larry
If you replace QUERY_STRING in the code above with THE_REQUEST then this works fine and does exactly as required within WordPress.

URL rewriting with Isapi_Rewrite 2 on Windows shared hosting fails partially

I have been forced to switch from IIRF to Isapi_Rewrite due to moving to a shared hosting environment from a VPS. The URL rewrites I was using under IIRF should work with minimal modifications, but for some unknown reason only one of the rewrites works.
Here's my httpd.ini for ISAPI_REWRITE V2:
[ISAPI_Rewrite]
RewriteEngine On
RewriteRule /buy-sell-assets$ /search/Assets.asp
ReWriteRule .*trucks-tractor\.html$ /search/NewSearch.asp?cat_id=157
RewriteRule .*trucks-rigid\.html$ /search/NewSearch.asp?cat_id=10
ReWriteRule .*trailers\.html$ /search/NewSearch.asp?cat_id=4
ReWriteRule .*helicopters\.html$ /search/NewSearch.asp?cat_id=481
ReWriteRule .*aircraft-fixedwing\.html$ /search/NewSearch.asp?cat_id=467
ReWriteRule .*aircraft-fixed-wing\.html$ /search/NewSearch.asp?cat_id=467
ReWriteRule .*buses\.html$ /search/NewSearch.asp?cat_id=3
ReWriteRule .*boats\.html$ /search/NewSearch.asp?cat_id=559
ReWriteRule .*cars\.html$ /search/NewSearch.asp?cat_id=8
ReWriteRule .*crushers\.html$ /search/NewSearch.asp?cat_id=635
ReWriteRule .*screens\.html$ /search/NewSearch.asp?cat_id=637
ReWriteRule .*cranes\.html$ /search/NewSearch.asp?cat_id=430
ReWriteRule .*equipment\.html$ /search/NewSearch.asp?cat_id=12
The really odd thing is that the rewrite rule
RewriteRule .*trucks-rigid\.html$ /search/NewSearch.asp?cat_id=10
works, but none of the others do. They are all pointing to the exact same script, so I'm at a complete loss as to why the others aren't working.
Here's the working URL:
http://www.atn.co.za/buy-sell-assets/trucks-rigid.html
Here's one of the non-working URLs:
http://www.atn.co.za/buy-sell-assets/trailers.html
Why should one work and not the others? This is an incredibly frustrating issue, I've been trying various permutations for about four hours now and I'm about to do something drastic :(
If anyone can provide any insight or assistance on this I'd really appreciate it.
Try using the following format:
RewriteRule /buy-sell-assets/trucks-tractor\.html$ /search/NewSearch.asp?cat_id=157 [I,L]
make sure each rule ends with [NC,L] or you'll have all your pages pointing at one script.

Resources