Apache RewriteCond not working for static files - mod-rewrite

I have two copies of the website in separate directories for different languages (Spanish and English) and the directory structure is as follows
+ /var/www/website
|- es
|- en
The es directory serves the Spanish version of the website and en serves the English version (default language).
The URL schema would be like
# English version
https://example.com/
https://example.com/en/ -> Redirects to https://example.com/
# Spanish version
https://example.com/es/
The static files are served from the respective directories only.
Now, I have the following Apache2 configuration
<VirtualHost *:443>
# The primary domain for this host
ServerName example.com
DocumentRoot /var/www/website
<Directory /var/www/website>
Require all granted
AllowOverride all
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP:Accept-Language} ^es [NC]
RewriteRule ^$ /es/ [R]
RewriteCond %{HTTP:Accept-Language} ^en [NC]
RewriteRule ^$ /en/ [R]
RewriteCond %{HTTP:Accept-Language} !^en [NC]
RewriteCond %{HTTP:Accept-Language} !^es [NC]
RewriteRule ^$ /en/ [R]
</Directory>
</VirtualHost>
I'm facing a few problems with the configuration
https://example.com/es/ and https://example.com/en/ are working but static files are not loading and the URL for the static files looks like https://example.com/image.png which has to be https://example.com/es/image.png (for Spanish) and https://example.com/en/image.png (for English)
https://example.com/en/ should be redirected to https://example.com/ and the English website should be served, whereas the reverse is happening.

Let's first understand what is happening here.
With rules like this
RewriteRule ^$ /es/ [R]
you are redirecting requests to / to /es/.
Redirecting means, the server will tell the browser to go search for the content at some other place.
The browser will then send another request to /es/. This will not be rewritten nor redirected as there is no matching rule.
You html file apparently contains references with absolute URLs like this:
<img src="/image.png" />
Your browser will therefore send a request for /image.png, which is not redirected, nor rewritten.
There are different ways how to solve that:
1. Update your html/code to absolute URLs with the right path
Like this:
<img src="/es/image.png" />
That's the best solution imho. Depending on how you generate the content, there might be an option to set the base URL of the project.
1b. Make the webserver do these substitution on the fly for you
You could think about whether you want apache to make these substitutions for you, e.g. using mod_substitute, but there might be cases you cannot catch with this approach. I would not recommend it.
2. Update your html/code to relative URLs
I.e.
<img src="image.png" />
This sounds nice on first sight, but can become ugly if you're having complex page structure, e.g. /es/foo/bar/somepage.html would need <img src="../../image.png" /> to reference /es/image.png.
It can become especially tricky if you want to serve the same content under /es/foo and /es/foo/ (without redirecting one or the other). The two would need a different relative path to the image.
3. Rewrite requests for /image.png
In theory, you could let Apache rewrite requests for /image.png to either /es/image.png or /en/image.png depending on the accept-language header.
I would not recommend that, as it leads to strange behavior. E.g. assume a user consciously decides to visit /en/ even though his language settings prefer Spanish. The browser would then request /image.png and the server would deliver - based on the language settings - the Spanish variant of the image. While the HTML shows the English content.

Related

redirect subdomain to page unless other page is called

i am trying to redirect all subdomains with more than 2 letters :
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^([^\.]{2,})\.domain\.com$ [NC]
RewriteRule .* index.php?page=static&subject=%1 [L,QSA]
for example : about.domain.com to display content of domain.com/?page=static&subject=about
but the URL remains about.domain.com in the browser
as well as if you're on about.domain.com and requested another page on that domain ( all pages go through index.php?page=blablabla) you need to be redirected back to domain.com/(whatever requested)
Same-domain internal rewrites can be done with the [P] (proxy) option.
If you need to reverse proxy a URL from the same virtual host config, you might be able to get away with a [P] rule, but if the domain of the internal request is from a different virtual host (or on a different box entirely) you probably need to look at a ProxyPass config.
In either case you will need mod_proxy installed and enabled.

.htaccess image redirection for specific images on one to one basis

I used to have a site up and running on a domain of mine, that I have since taken down. However in that site I had a handful of specific images that I had either shared with other sites.
Its been a while since I visited the logs of that domain, and I realize that there is about 2 dozen images coming up as 404, and I recognize them as the images shared. What I want to do is put those images on another domain of mine, and have any requests coming for those images get rewritten with the other domains url where the images now reside.
Is this possible, to specify images on a one to one basis and have them point to there counter parts on the other domain? I've seen it done where people are being not so selective but nothing in terms of what I would like to do.
Yes, you can do that with .htaccess.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
Options +FollowSymLinks
RewriteRule ^img/path/to/file1.jpg$ http://newdomain.com/new/path/to/file1.jpg [L,R=301]
RewriteRule ^img/path/to/file2.jpg$ http://newdomain.com/other/new/path/to/file2.jpg [L,R=301]
RewriteRule ^img/path/to/(file3.jpg|file4.jpg)$ http://newdomain.com/typical/new/path/to/$1 [L,R=301]
</IfModule>
Considering http://olddomain.com/img/path/to/file1.jpg is one of the image files and the .htaccess is in the document root of olddomain.com, this should do the job. If you can't match the old and new file names against some regular expressions you'd need to have a line with RewriteRule for each missing image.

Using mod_rewrite or htaccess to apply 301's to entire site structure, with URL's built using query strings

I am taking over an old website, and need to change the domain name.
The current domain is http://www.example.com/folder/ and the new domain is http://example.school.nz
An example of an existing and desired URL is:
Before: http://www.example.com/folder/index.php?page=sport
Desired: http://example.school.nz/about-us/sport
The site is built using CMSMS (http://www.cmsmadesimple.org), so pages and URL's are generated through the CMS, although it's easy enough to export a list of URL's.
Ideally I could set up 301 redirects for the entire site so the user doesn't get 404'd. Any clues to the easiest way to accomplish this?
It depends on how general you want things to be, but this set of rules will do what you asked in your question:
RewriteCond %{HTTP_HOST} .*
RewriteCond %{QUERY_STRING} page=sport
RewriteRule ^folder/index.php http://example.school.nz/about-us/sport? [L,R=301]

Apache2 redirect all but some pages back to http using vhosts

I am using rewrite rules with Apache 2 to redirect certain types of pages to HTTPS using vhosts. These are anything that starts with mydomain.com/users. In other words, all pages having to do with users and their information should be on HTTPS. I want to redirect all other pages to HTTP.
What happens now is that when a user goes to a /users page, he is redirected fine to HTTPS. But when he navigates away from the /users area, I can't get the redirect back to HTTP.
I need the rules and conditions to rewrite anything that is NOT /users/* to HTTP. In other words, please help me fill in the blanks:
RewriteCond %{SERVER_PORT} ^443$
RewriteCond %{REQUEST_URI} __blank__
RewriteRule __blank__ http://mydomain.com%{REQUEST_URI} [R=301,L]
In researching this, there are a few things I am trying to avoid. I need a wildcard under /users because I am developing the app and often add pages under users (it's a Rails app).
I understand that it is not easy to do a NOT match with regular expressions. All I am trying to do here is have the bulk of the site run on HTTP except the /users/* pages on HTTPS.
Also, yes I have a valid cert and yes I have verified that the Apache2 rewrite mod works. I can get all URLs rewritten to HTTP no problem. How do I NOT rewrite ones that start with /users in the REQUEST_URI? I think I have actually tried about every answer on this site so far...
There quite a few answers for this sort of questions, -- you just need to search this site a bit. Yes, they do not answer your question 100% straight away (as everyone has slightly different requirements -- like different page name etc) but the whole approach is the same.
In any case -- here how it can be done:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
# don't do anything for images/css/js (leave protocol as is)
RewriteRule \.(gif|jpe?g|png|css|js)$ - [NC,L]
# force https for /users/*
RewriteCond %{HTTPS} =off
RewriteRule ^/users/ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# force http for all other URLs
RewriteCond %{HTTPS} =on
RewriteCond %{REQUEST_URI} !^/users/
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# your other rewrite rules below
These rules need to be placed inside VirtualHost directive BEFORE any other rewrite rules (if such present). If placed elsewhere some small tweaking may be required.
They will
force HTTPS for all resources in /users/,
do nothing for images, css styles and JavaScript files (to be precise, for files with those extensions)
and will force HTTP for all other URLs
IMPORTANT NOTE: It is very likely that these rule will not work for you straight away. That is because modern browser do CACHE 301 redirects from your previous attempts. Therefore I recommend testing it on another browser and change 301 to 302 during testing (302 is not cached) .. or clear all browser caches (maybe even history) and restart browser.

How to deal with "#" in a query string in mod_rewrite?

I asked this question about rewriting old "ugly" links into seo friendly ones.
I need to "extract" some information after the "sharp" symbol in some urls. I've created a regular expression to it but it can't seen to work.
After my question, I created this logic for this url for example, script.php?mode=full&id=23:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /script\.php\?mode=full&id=([0-9]+)\ HTTP/
RewriteRule ^script\.php$ fix_old_urls.php?phpfile=script2&id=%1 [NC,L]
But I'm working in a legacy application, and I need to extract the value after the sharp symbol in some pages, in the example url script.php?mode=full#23:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /script\.php\?mode=list\#([0-9]+)\ HTTP/
RewriteRule ^script\.php$ fix_old_urls.php?phpfile=script&id=%1 [NC,L]
(in fix_old_urls I properly redirect with a 301 code).
The first one works, but not the second. To me it looks like it`s the same logic in both. What am I'm doing wrong?
Anchor information (the part starting with the #) is never actually sent to the server. It's handled completely by the browser, and thus you can't touch it with mod_rewrite (nor can you access it via server-side scripting languages). The only things that can see it are the browser and client-side scripts (like Javascript).

Resources