I'd like to know if there is a way of changing the relative document root for extra security. I'll try to explain myself through the following example:
/root
/app
/public
Say an www.example.com request to the web server would point to the root folder.
I was wondering if there was a configuration, for instance through an .htaccess file located in said root folder, that would make the server point to the public folder instead, therefore having any remote paths always be relative to said public folder.
In this instance, www.example.com/app would request an app folder inside of public, instead of an app folder inside of root, leaving the latter to be inaccessible from a remote url request.
In the same manner, www.example.com/public would request a public folder inside of our root public folder and so forth.
I've read various topics like this one that mention using a custom .htaccess configuration to achieve something similar, but it requires the manual configuration of the request url in said file, while my intention is for it to work without further configuration no matter where you host the application.
Another possible solution I've seen is doing a hard redirect through the .htaccess file, which does not solve anything actually.
Feel free to edit this post as I might have had a hard time trying to get my point across.
You can use this simple .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*)$ /public/$1 [L]
</IfModule>
Any request on your server will point to the public folder.
Inside the public folder you can add an extra .htaccess file handling your site rules.
Also you can Host multiple sites on One webserver. You can combine making VirtualHosts and Alias using mod_alias mentioned before
In this example is suposed to have your own server (either dedicated or VPS)
By using Virtualhosts you can tell to the webserver when you recieve a request to www.example.com to serve content from a specific folder.
An example Virtualhost of it is:
<Virtualhost *:80>
ServerName ^domain_or_ip^
DocumentRoot ^path of the public folder^
DirectoryIndex index.php home.php index.html index.htm
ErrorLog ^path for a file containing php errors^
CustomLog ^path for logging whitch browser and ip visited your site^ combined
</Virtualhost>
I suggest that you point your server to the public folder anyhow, as it is much more secure, you could see that all frameworks behave the same way, they all have a "public" folder where the server points to.
In the public folder you have one point of entry to your scripts, like
index.php
and from this entry you will communicate with your application.
Of course you can still work the way you requested, and it will work great, but who knows maybe you will miss something and someone could access and view your "inner" files.
You're on Apache web server? If I understand correctly, you're looking for Virtual Directories. Usually, we have to put our web application inside the document root of Apache in order to make the application accessible from the network. However, there is a trick to make the web application still accessible even though we put it outside of Apache's document root. Please read up on that here: http://w3shaman.com/article/creating-virtual-directory-apache
Credits to W3Shaman.com, obviously.
Related
My team's server is set up in such as way: We have one domain name, which seems like already a subdomain of the company's domain. We want to host multiple applications under this one domain. We'd even like to have a production version and staging version for each of the apps on the server.
Document root is an empty folder. Applications sit outside of the document root.
we are trying to use the first token in the URL path to find out which app we try to access, then somehow redirect to it (internally or externally).
Here is a structure equivalent to how the directories are organized.
/usr/local/var/www <- Document Root
/usr/local/var/app1 <- application 1
------------------/public/index.php
------------------/public/css
/usr/local/var/app2 <- application 2
/usr/local/var/app1.stg <- application 1 staging version, code is exactly the same as application1
/usr/local/var/app2.stg <- application 2 staging version, code is exactly the same as application2
Here are the relevant settings in httpd.conf
DocumentRoot /usr/local/var/www
<Directory "/usr/local/var/www">
AllowOverride None
Require all granted
</Directory>
Alias "/app1" "/usr/local/var/app1"
Alias "/app2" "/usr/local/var/app2"
<VirtualHost *:80>
# rewriting rules to make the routing work
# There is only one vhost so it can actually be removed
</VirtualHost>
When we access https://sub.domain.com/app1, we expect to go to app1
When we access https://sub.domain.com/app1.stg, we expect to go to app1.stg
The applications are written in PHP. This server configuration means we have to include the "path to the application" in the routes and rewrite rules, and use the "full absolute path" in all the resource references.
For example, a route will look like
$router->map("GET", "/app1/action", SomeController);
A css reference will be: (even though relative path is given, it behaves just like a relative path to the DocRoot (with "/" in front). You can see it in this detailed post)
<link href="app1/public/css/style.css" type="text/css" rel="stylesheet"/>
These will be sufficient to make both apps work, but the staging version is not going to work, because it contains EXACTLY THE SAME copy of code (which is how it's intended to be, to test out in staging environment, then push to production environment).
If I want both versions to work, I have to code the paths dynamically, namely using CONTEXT_DOCUMENT_ROOT or some other server variable to figure out which app version it's in, and have two copies of routes, one starting with app1, the other app1.stg. I also have to have separate rewriting rule for each version.
QUESTION
With the server setup restriction applied (one domain name, distinguish apps with the way I described, etc..), is it possible to use only relative paths, write routes with respective to only the app itself? Some like:
<link href="css/style.css" type="text/css" rel="stylesheet"/>
$router->map("GET", "/action", SomeController);
In other words, I have to change the server setup within the constraints, so that the app can be written in a way without caring how the server is set up.
I know one way is to use different ports for each app/version, but apparently the server admin doesn't like the idea.
I've broken down the problem into steps in this question. It's quite long but if you are willing to follow through, it should provide much more details.
If the question is not clear enough, the per-user directory looks quite like what I want to achieve. But instead of user directory, I want the app directory in place of it. Of course I never used per-user directory so I dont know if it actually behaves the way I think it does.
So I understand that we can have multiple hostnames in /etc/hosts mapped to one IP address. Can I just use that hostname as the ServerName in apache config, and access in the browser by typing that hostname? The website is for internal usage so should only be accessed within company's network.
In /etc/hosts:
123.45.67.89 app1.team-server-name app2.team-server-name
In httpd.conf:
<VirtualHost>
ServerName app1.team-server-name
DocumentRoot /usr/local/var/app1/public
</VirtualHost>
<VirtualHost>
ServerName app2.team-server-name
DocumentRoot /usr/local/var/app2/public
</VirtualHost>
This is quite the lengthy question, thank you for providing so much detail.
I would opt for a different approach than you are currently attempting. Instead of trying to serve each of these applications out of a folder, set up each of them as a domain based vhost. Use something like app1.local or whatever for the hostname and be sure to add the entries to your /etc/hosts file under 127.0.0.1. Make sure the listen directive for these vhosts is on the loopback (127.0.0.1:80). Each of these apps should function as if they were installed at the document root of their own server. All the CSS should assume its at 'css/style.css' relative to /.
Now that you have all of the apps setup on the loopback, you can setup a reverse proxy from the vhost listening on the public interface to proxy all of the application locations to their appropriate loopback vhost after you remove the /app1 prefix from the request.
I haven't used Apache 2.x for a very long time, but the concepts are the same as nginx.
location /foo {
rewrite /foo/(.*) /$1 break;
proxy_pass http://app1.local;
proxy_redirect off;
proxy_set_header Host $host;
}
The biggest issue with this approach is that the applications that are being proxied either need to use relative paths everywhere, or they need to have some kind of configurable prefix that is prepended to the urls. Most frameworks will support the prefix option. For Example: https://laravel.com/docs/5.6/urls This prefix can be used for asset (css/js/jpg) loading as well, but only from files that execute PHP.
I end up finding a solution with one compromise.
DocumentRoot "/usr/local/var/www"
Alias /app1 /usr/local/var/app1/public
<Directory "/usr/local/var/www">
RewriteEngine On
RewriteRule ^/?$ /app1/ [R,L]
RewriteRule (.*) /app1/$1 [R,L]
</Directory>
<VirtualHost *:80>
<Directory "/usr/local/var/app1">
Require all granted
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# calls index.php (REQUEST_URI is still the same as before)
RewriteRule ^ index.php [L]
</Directory>
</VirtualHost>
All relative paths can be rewritten normally.
Routes and requests will need to start with app name.
$router->map("GET", "/app1/hello2", SomeController);
// navigation bar. URI for another tab:
<li>Hello 2</li>
If we want to have multiple versions of the app, the main thing to do is to know which version we are in so the app can send the correct request uri. This can be done by checking the REQUEST_URI and remember which version is being called when index.php is called up. Then in the request (e.g. navigation src), append it in front of the action.
There are different ways to do this, such as writing your html templates in php, so you can access php variables. I used twig so I can pass the value to the twig templates from php. But I still don't like to have all these stuff in my static code, so I decided to just get rid of the staging version.
If the project is serious enough to require a staging version, then a better suitable environment should be provided.
I'm very new to php and web , now I'm learning about oop in php and how to divide my program into classes each in .php file. before now all I know about php program, that I may have these files into my root folder
home.php
about.php
products.php
contact.php
So, whenever the client requests any of that in the browser
http://www.example.com/home.php
http://www.example.com/about.php
http://www.example.com/products.php
http://www.example.com/contact.php
No problem, the files will output the proper page to the client.
Now, I have a problem. I also have files like these in the root folder
class1.php
class2.php
resources/myFunctions.php
resources/otherFunctions.php
how to prevent the user from requesting these files by typing something like this in the browser ?
http://www.example.com/resources/myFunctions.php
The ways that I have been thinking of is by adding this line on top of every file of them exit;
Or, I know there is something called .htaccess that is an Apache configuration file that effect the way that the Apache works.
What do real life applications do to solve this problem ?
You would indeed use whatever server side configuration options are available to you.
Depending on how your hosting is set up you could either modify the include path for PHP (http://php.net/manual/en/ini.core.php#ini.include-path) or restricting the various documents/directories to specific hosts/subnets/no access in the Apache site configuration (https://httpd.apache.org/docs/2.4/howto/access.html).
If you are on shared hosting, this level of lock down isn't usually possible, so you are stuck with using the Apache rewrite rules using a combination of a easy to handle file naming convention (ie, classFoo.inc.php and classBar.inc.php), the .htaccess file and using the FilesMatch directive to block access to *.inc.php - http://www.askapache.com/htaccess/using-filesmatch-and-files-in-htaccess/
FWIW all else being equal the Apache foundation says it is better/more efficient to do it in server side config vs. using .htaccess IF that option is available to you.
A real-life application often uses a so-called public/ or webroot/ folder in the root of the project where all files to be requested over the web reside in.
This .htaccess file then forwards all HTTP requests to this folder with internal URL rewrites like the following:
RewriteRule ^$ webroot/ [L] # match either nothing (www.mydomain.com)
RewriteRule ^(.*)$ webroot/$1 [L] # or anything else (www.mydomain.com/home.php)
.htaccess uses regular expressions to match the request URI (everything in the URL after the hostname) and prepends that with webroot/, in this example.
www.mydomain.com/home.php becomes www.mydomain.com/webroot/home.php,
www.mydomain.com/folder/file.php becomes www.mydomain.com/webroot/folder/file.php
Note: this will not be visible in the url in the browser.
When configured properly, all files that are placed outside of this folder can not be accessed by a regular HTTP request. Your application however (your php scripts), can still access those private files, because PHP runs on your server, so it has filesystem access to those files.
I still don't quite understand why we must keep index.php in a public directory instead of in the root directory.
root/of/project
public/
index.php
.htacess
(html, image, css, etc)
Then, write the following in our virtual host file:
DocumentRoot /path/to/myapp/app/public
<Directory "/path/to/myapp/app/public">
# other setting here
</Directory>
The .htaccess file then redirects all non-existing URLs to index.php:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
I notice that most frameworks do so, such as Symfony and Zend, just as this tutorial. What is the actual benefits really by having the trouble of modifying the virtual host file?
Why shouldn't we do have this below instead without modifying the virtual host file? Is it a security risk or something?
root/of/project
index.php
.htacess
public/
(html, image, css, etc)
If keeping index.php and modifying the virtual host file is better, how can we modify the virtual host file in the live server then? Let's say I have this domain name, http://my-website.com/ and I access it on my browser, what I see first is not the web page but the directories below untill I click the public directory then I see the home page,
root/of/project
public/
index.php
.htacess
(html, image, css, etc)
I assume that this is the same for Zend or Symfony project as well without being able to modify the virtual host file in the live server. I am no good at these frameworks, I will see this below if I upload my Zend project to the live server,
So, how do you deploy your Zend or Symfony project to your live server to see your web page right away?
It is a very good idea to keep index.php outside of your project root directory because of one simple reason:
You don't want your user to access any files other that one in public folder (index.php, css, js etc). When you will put index.php in root folder you will be also able to access composer.json file for example which is a security risk - a potential hacker will know what packages are you using, in which versions so it's easier for him to perform attack.
When it comes to your hosting - you should have some public_html folder on your root directory which is meant to be public folder (web) of your Symfony app and you should also be able to keep files outside of public folder. If you don't - you really need to think about changing hosting partner
EDIT:
Answering your comment. Let's assume you have public_html folder on your hosting and you want to deploy Symfony app which should be accessible directly on http://your-domain.com. Then you should put whole Symfony project anywhere (but outside of public_html folder) and make a public_html folder a symbolic link to web folder of your Symfony project. This action is equivalent of editing virtual host and changing DocumentRoot which, I assume, you are not able to do.
You can also check my answer on another question to get more clarification
I'm developing some web based application based on PHP.
I have some folder structure that will be located inside the public html file.
I'd like to make it work so that when a user types for ex. http://mysite.com/ he/she gets into http://mysite.com/public but I don't want the user to know that he/she is inside public, the user should think that his directly inside public_html folder.
Any hints?
P.S. I'm doing it on hosted server, so I have access with only Cpanel, I'm not the admin of the server.
You either need to use mod_alias or mod_rewrite for this. How much of cPanel is available to you? How much does you host let you do?
I'll just have to have a look through my WHM server to work out how to do Aliases, but you can do rewrites with a .htaccess file. I would recommend Aliases over rewrites thought, as they are less complicated and less resource-hungry.
EDIT
Just been into my root login for our WHM/cPanel based server, and I can't find any way to use mod_alias - I think this is probably because it would require an Apache restart. You will have to use mod_rewrite.
Put this in a .htaccess file in public_html:
RewriteEngine on
RewriteRule (.*) public/$1 [L]
You can set up an addon domain and point it to /public_html/public directory.
Edit:
Parked domain should work too.
I'm developing an application in Symfony and on localhost (XAMPP) I want to simulate the same conditions as on the webserver.
The web server is configured as follows:
/www => mydomain.com
/foo => foo.mydomain.com
/bar => bar.mydomain.com
...
I'm going to put my Symfony application into /www direcotry so there'll be:
/www
/www/apps
/www/apps/frontend
/www/apps/frontend/...
/www/apps/backend
/www/apps/backend/...
/www/cache
/www/config
... and so on...
/www/web
The thing is that the document root is still set to the /www directory but Symfony expects it in the /www/web.
Of course it will work if I call http://mydomain.com/web but I guess you understand this is quiet stupid solution.
So my question is: Is there any way how can I change/bypass the default document root setting using .htaccess or whatever?
EDIT: I solved it.
I don't know much about Symfony but /web is supposed to be the document root. All the other directories should be outside the document root for security reasons for one, and to avoid the /web part in the URL for another. But it looks like you already know that.
If you can edit the web server's configuration, try to reflect that and set DocumentRoot to the web directory.
If you can't do that: It's not possible to change the DocumentRoot in a .htaccess file but it is possible to rewrite all requests so they go to /web internally using mod_rewrite. It's kludgy, but probably the best solution if you can't influence DocumentRoot.
I'm not a mod_rewrite guru so I can't provide an example (I would have to test it first and I can't do that right now) but I'm sure somebody will. Maybe add the mod_rewrite tag to your question.
Update: Untested but should work. Put into a .htaccess file in /www:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !^/web/
RewriteRule .* /web/%1 [QSA]
you would then need to change your configuration files to use http://www.domain.com/ instead of http://www.domain.com/web/ of course.
I can't say whether that interferes with any other .htaccess rules on the Symfony end - you'd have to try out.
I you got hand on apache config, the better is to move document root from /www to /www/web in you virtualHost config and allow php (if restricted by open_basedir configuration directive) to access the whole /www directory.
Change the way symfony expects your directory to be named :
// config/ProjectConfiguration.class.php
class ProjectConfiguration extends sfProjectConfiguration
{
public function setup()
{
$this->setWebDir($this->getRootDir().'/www/or/whatever/directory');
}
}