point root to sub-directory with .htaccess - apache

i have the rule to redirect all request to https and point to index.php
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:CF-Visitor} !{"scheme":"https"}
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Protocols h2 http/1.1
the root directory is htdocs, but i need change it to point to htdocs/public because some framework implement public folder has root. the problem is that i fin that example:
RewriteRule ^subfolder/$ /yourfile.php [L]
It's not clear to me how to implement it.
update:
my .htaccess file is in the root directory: htdocs, then index.php is located in htdocs/public, in this subdirectory I don't have the .htaccess
finally what I am looking for is that when entering a url like:
https://your-example.com/
https://www.your-example.com/
https://www.your-example.com/test-foo/
https://www.your-example.com/test-foo?data=data&foo=foo
all these requests point to index.php in the subdirectory:
htdocs/public/index.php
update 2:
my current routing in /public/.htaccess:
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

the root directory is htdocs, but i need change it to point to htdocs/public because some framework implement public folder has root.
Ordinarily, if you have access to the server config then you would "simply" change the DocumentRoot in the server config to point to the /public subdirectory. Alternatively, if you have access to the directory above the document root (as you appear to) then move the file structure "up" a level, so that the files in the /public subdirectory are moved to the document root (ie. htdocs/) and the framework/system files are in a directory above the document root, outside of the public HTML space (as they should be).
However, if you don't have access to the server config and/or are unable to move the files, and you have a /public subdirectory off the document root then proceed as follows...
I assume your current HTTP to HTTPS rule/redirect is working OK for you (since this is specific to Cloudflare)? However, the rule you posted does not route anything to index.php as you appear to suggest and the Protocols directive is not permitted in .htaccess (and should be triggering an error) - so not sure what that is doing there?
You need to add a rewrite to the root .htaccess file (ie. /htdocs/.htaccess) that rewrites all requests to the /public subdirectory. And create an additional .htaccess at /htdocs/public/.htaccess that routes all requests to public/index.php (your front-controller).
For example, try it like this:
# htdocs/.htaccess
RewriteEngine On
# Redirect HTTP to HTTPS
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:CF-Visitor} !{"scheme":"https"}
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Rewrite all requests to the "/public" subdirectory
# You could do this unconditionally, depending on your requirements.
# ie. You don't necessarily need to check for existing files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) public/$1 [L]
Also consider canonicalising the www vs non-www hostname (ie. redirect one to the other). This would go in the root .htaccess file before or after the HTTP to HTTPS redirect (depending on requirements, ie. are you implementing HSTS?).
Create a second .htaccess file at htdocs/public/.htaccess with the following:
# htdocs/public/.htaccess
DirectoryIndex index.php
Options +FollowSymLinks -MultiViews -Indexes
RewriteEngine On
# Route all requests to "index.php" (front-controller)
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
UPDATE:
I quick analysis of your existing rules, but as I mentioned in comments, the version I described above is preferable.
my current routing in /public/.htaccess:
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
The RewriteBase / directive here is incorrect and will break the rules when located in the /public subdirectory. This would need to be either set to RewriteBase /public or removed altogether (preferable).
The QSA flag is not required since you are not including a query string in the substitution.
^(.*)$ - the capturing group is less efficient and not required (you are not making use of any backreferences here).
The <IfModule> wrapper is not required and should be removed. This would only be required if these directives are optional (they are not) and you are moving these directives to multiple servers where mod_rewrite might not be enabled.
The filesystem checks to make sure the request does not map to a directory (!-d) and is not a symbolic link (!-l) are generally not required (and consequently is an unnecessary overhead if they are not reqd). These should be removed, unless you specifically need to access filesystem directories (or symbolic links) directly (which is rare).

Related

Vue.js + Apache , how to write redirect rules for multiple entries?

I have a vue.js app which consists of 2 entry points (2 SPA's). one of them is index.html, which serves the client website and the other is for the platform (platform.html)
Following the Vue CLI documentation, I am using the following in my .htacess file
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
this only works if I only have index.html and when I type in myUrl.com/platform it doesn't change to the platform.
I have tried the following and can't make it work
<IfModule mod_rewrite.c>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^platform(.*)$ platform.html [L]
RewriteRule ^(.*)$ index.html [L]
</IfModule>
</IfModule>
Assuming that any URL prefixed with platform should be sent to platform.html and everything else to index.html then you could do something like the following in your root .htaccess file:
DirectoryIndex index.html
RewriteEngine On
# Optimisation - prevent rewritten requests for the front-controller being reprocessed
RewriteRule ^index\.html$ - [L]
RewriteRule ^platform\.html$ - [L]
# Prevent static resources being routed through the app
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Any URLs that start "/platform" (whole path segment only) are sent to "/platform.html"
RewriteRule ^platform($|/) platform.html [L]
# All other URLs are sent to "/index.html"
RewriteRule . index.html [L]
The RewriteBase directive is not required here.
You do not need the <IfModule> wrappers, unless these directives are optional (they are not). (It doesn't make sense to nest these wrappers in this way.) See my answer to the following question on the Webmasters stack for more discussion on this: Is Checking For mod_write Really Necessary?
Note that requests for the document root are not actually rewritten by the directives above, but are instead sent to index.html by the DirectoryIndex directive - this is often already configured on the server, so the directive may not be required here.
UPDATE: Since your URLs are like /platform/<subroute>, rather than /platform<something>, the regex in the above rule would be better as ^platform($|/), rather than simply ^platform, in order to match the whole path segment only and to avoid potentially matching too much, such as /platformsomething. (I've updated the code above.)
^platform($|/) matches platform or platform/something, but not platformsomething.

rewrite problems (htaccess)

Having some experience with procedural php I watched some tutorials about OOP and the MVC model (with php). Things start to get more clear and I wanted to put the theory to practice.
The tutorial I'm following works with an app folder and a public folder, both subfolders of the root directory. There's an index.php file in the public folder and a htaccess file that redirects all requests (in the public folder) to none existing files to index php. The code in that file is:
<IfModule mod_rewrite.c>
Options -Multiviews
RewriteEngine On
RewriteBase /public
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
</IfModule>
That works fine.
In the root folder there is also a htaccess file with the purpose of redirecting all url requests to the public folder (in case /public/ is not in the url. The code in that file is:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
</IfModule>
That goes wrong, and it's the second RewriteRule that causes the problems. If I for example browse to
www.mywebsite.com
the browser redirects to www.mywebsite.com/public/index.php
But if I browse to www.mywebssite.com/shop (shop is not an existing file) I suppose the browser redirects to www.mywebsite.com/public/index.php?url='shop', but instead there is an internal server error. It seems to be the second RewriteRule that causes the problem.
What could be the problem?
I am on mobile I haven't tested it but looks like you could be reaching out to maximum redirect limits here why because your condition in your root htaccess isn't looking good to me, try this once.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteCond %{REQUEST_URI} !^/public/? [NC]
RewriteRule (.*) public/$1 [L]
</IfModule>
Issues in OP's approach: You haven't mentioned any condition to when it should redirect so it doesn't know when to stop hence it's creating a loop here IMHO.

htaccess rewrite rules to remove multiple subfolders from a URL

Due file system sub-directory constraints I will most likely reach I want to separate the /users folder into /users/a/username, /users/b/username, /users/c/username, etc.
So the data on the server for a user would be in:
www.domain.com/users/a/username/, www.domain.com/users/b/username/, etc
I want the URL to be:
www.domain.com/users/username/
Optionally to avoid duplicate content a 301 redirect from www.domain.com/users/a/username/ to www.domain.com/users/username/ would also be good.
Currently I have a rewrite for a single sub-directory (see below) but I'm confused how this can be done efficiently for all of the alphabetical sub-directories.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^users/(.*)$ users/a/$1 [L,NC]
I have checked this site and all seem to hide the first sub-directory e.g. domain.com/folder1/filename.html => domain.com/filename.html but nothing in more depth.
Put this code in your htaccess (which has to be in root folder)
Options -Indexes -MultiViews
RewriteMap lowercase int:tolower # this line in your apache file configuration
RewriteEngine On
RewriteCond %{THE_REQUEST} \s/users/[a-z]/([^/\s]+)\s
RewriteRule . /users/%1/? [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^users/([A-Za-z])([^/]+)/$ /users/${lowercase:$1}/$1$2/ [L]

Mod_Rewrite rewriting directory I dont want it to

So I am using Kohana which is useful if you know it, but not needed to assist me.
I have the following mod_rewrite rules:
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/store/.*$
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php [L]
So I am trying to rewrite all requests for files and directories that do not exist to index.php.
However, I want any request sent to mydomain.com/store/* to go through as there is another htaccess file in the store directory that does work there. That does not seem to be working at the moment. Any ideas?
Full htaccess:
# Turn on URL rewriting
RewriteEngine On
# Installation directory
RewriteBase /
#ErrorDocument 404 http://www.mydomain.com/404Page.html
#Options +FollowSymlinks
# Protect hidden files from being viewed
<Files .*>
Order Deny,Allow
Deny From All
</Files>
RewriteCond %{REMOTE_ADDR} !^myip
RewriteCond %{REQUEST_URI} !^/maintenance\.html$
RewriteRule ^(.*)$ http://www.mydomain.com/maintenance.html [R=307,L]
##301 Redirect Rules##
#some 301 redirects i did not include here
##Kohana Redirect Rules##
# Protect application and system files from being viewed
RewriteRule ^(?:application|modules|system|kohana|vendors)\b.* http://www.mydomain.com/ [L]
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/?store/
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php [L]
Try this condition:
RewriteCond %{REQUEST_URI} !^/?store/
There is no need to check the characters after the directory. I made the first slash optional if I remeber correctly is the first slash only visible if your server configuration does not contain a tailing slash.
The issue turned out to be in the .htaccess file in the store directory not the one in the webroot. Thanks all, and sorry for my stupidity. IF anyone wants to leave comments on how to debug something of this nature for future users that would be awesome.

Use mod_rewrite to redirect from example.com/dir to www.example.com/dir

Assume / is the document root of my domain example.com.
/.htaccess
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
/dir/.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /dir/index.php [L]
</IfModule>
I know how to redirect example.com/dir to www.example.com/dir, because /.htaccess does the very job.
However, the trick here is that I have to keep /dir/.htaccess to serve up virtual directories (such as /dir/state/AK/35827/ which aren't actual directories) if you know what I mean.
Problem is, if I keep /dir/.htaccess, a request of:
http://example.com/dir/state/AK/35827/
DOES NOT redirect to:
http://www.example.com/dir/state/AK/35827/
as would:
http://example.com/
redirect to:
http://www.example.com/
Not sure if I made it clear.
Basically, how to make http://example.com/dir/state/AK/35827/ correctly redirect to http://www.example.com/dir/state/AK/35827/ AND I can serve virtual URLs?
If you do have access to your apache VirtualHosts configuration then you need:
<VirtualHost *:80>
ServerName example.com
Redirect permanent / http://www.example.com/
</VirtualHost>
This will succesfully redirect http://example.com/ to http://www.example.com/ and http://example.com/dir/state/AK/35827/ to http://www.example.com/dir/state/AK/35827/
The "problem" here is that mod_rewrite does not "inherit" the parent config (.htaccess) by default. The mod_rewrite directives in the subdirectory completely override the mod_rewrite directives in the parent directory (different to other modules).
You either need to:
Copy the canonical www redirect from the parent .htaccess file into /dir/.htaccess. But code duplication is not desirable.
OR: Enable mod_rewrite inheritance in the child .htaccess file:
RewriteOptions inherit
This effectively "copies" the mod_rewrite directives from the parent .htaccess file. However, if you have other directives, this might not work as expected. Note that this "copies" the directives, without changing the directory-prefix.
OR: do everything in the parent .htaccess file. Having a single .htaccess file is probably the preferred solution. For example:
RewriteEngine on
# Canonical redirect
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
# Virtual directories...
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^dir/ dir/index.php [L]