A web site located on a local computer is accessed in a browser through the URL localhost and normally served by a local Apache server. There are two parts to this process. The first is the resolution of the name localhost to the IPv4 loopback address 127.0.0.1 which is configured in the local computer’s hosts file.
On macOS this is /private/etc/hosts:## # Host Database # # localhost is used to configure the loopback interface # when the system is booting. Do not change this entry. ## 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost
Throughout the remainder of this article the URL localhost is synonymous with http://localhost, 127.0.0.1 and http://127.0.0.1.
The second part is the configuration of the local Apache server to tell it where to locate and serve the web site’s files. This location is known as the DocumentRoot and is normally configured in a file named httpd.conf. The location of this file will differ depending on how your computer provides a local Apache environment. For XAMPP this is /Applications/XAMPP/xamppfiles/etc/httpd.conf and below is part of that file showing the default DocumentRoot configuration:
# # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # DocumentRoot "/Applications/XAMPP/xamppfiles/htdocs" <Directory "/Applications/XAMPP/xamppfiles/htdocs"> # # Possible values for the Options directive are "None", "All", # or any combination of: # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews # # Note that "MultiViews" must be named *explicitly* --- "Options All" # doesn't give it to you. # # The Options directive is both complicated and important. Please see # http://httpd.apache.org/docs/trunk/mod/core.html#options # for more information. # #Options Indexes FollowSymLinks # XAMPP Options Indexes FollowSymLinks ExecCGI Includes # # AllowOverride controls what directives may be placed in .htaccess files. # It can be "All", "None", or any combination of the keywords: # Options FileInfo AuthConfig Limit # #AllowOverride None # since XAMPP 1.4: AllowOverride All # # Controls who can get stuff from this server. # Require all granted </Directory>
For requests to localhost, the Apache server in XAMPP serves the file index.php located in the DocumentRoot folder /Applications/XAMPP/xamppfiles/htdocs/:
<?php if (!empty($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'])) { $uri = 'https://'; } else { $uri = 'http://'; } $uri .= $_SERVER['HTTP_HOST']; header('Location: '.$uri.'/dashboard/'); exit; ?> Something is wrong with the XAMPP installation :-(
Line 8 of index.php performs a redirect from localhost to localhost/dashboard/ where Apache serves the XAMPP Welcome Page generated by the file index.html located in /Applications/XAMPP/xamppfiles/htdocs/dashboard/:
To have Apache serve your own web site content there are two main options. The first is to place it within the default DocumentRoot. The second is to place it outside of the default DocumentRoot and use the Alias directive to map a URL to this location.
In the following examples, the generic index.php file below is placed within the DocumentRoot or aliased location and simply displays its name and location within the server’s folder structure:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>XAMPP Test</title> </head> <body> <p style="font-size:1.5em;">This page was generated by <?php echo $_SERVER['SCRIPT_FILENAME'];?></p> </body> </html>
1. Place Web Site Content Within the DocumentRoot
Perhaps the easiest option – and the one requiring least change – is to place your web site content within the default DocumentRoot folder /Applications/XAMPP/xamppfiles/htdocs/ remembering to replace, rename or delete the existing index.php there.
A request to localhost then serves the following page:
An alternative is to re-define the DocumentRoot configuration in /Applications/XAMPP/xamppfiles/etc/httpd.conf to point to another folder and place your web site content in this new location. This folder does not have to be within the /Applications/XAMPP/ folder structure. Below the DocumentRoot is changed to /User/steve/Sites/mysite:
# # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # DocumentRoot "/User/steve/Sites/mysite" <Directory "/User/steve/Sites/mysite"> # # Possible values for the Options directive are "None", "All", # or any combination of: # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews # # Note that "MultiViews" must be named *explicitly* --- "Options All" # doesn't give it to you. # # The Options directive is both complicated and important. Please see # http://httpd.apache.org/docs/trunk/mod/core.html#options # for more information. # #Options Indexes FollowSymLinks # XAMPP Options Indexes FollowSymLinks ExecCGI Includes # # AllowOverride controls what directives may be placed in .htaccess files. # It can be "All", "None", or any combination of the keywords: # Options FileInfo AuthConfig Limit # #AllowOverride None # since XAMPP 1.4: AllowOverride All # # Controls who can get stuff from this server. # Require all granted </Directory>
A request to localhost now serves the following page:
2. Place Web Site Content Outside the DocumentRoot
There’s another pre-defined location within XAMPP where you can place your site files. This is /Applications/XAMPP/xamppfiles/apache2/htdocs/. Navigating to the end of the Apache configuration file /Applications/XAMPP/xamppfiles/etc/htppd.conf we see:
# XAMPP Include etc/extra/httpd-xampp.conf Include "/Applications/XAMPP/xamppfiles/apache2/conf/httpd.conf"
Below is the /Applications/XAMPP/xamppfiles/apache2/conf/httpd.conf file passed as an argument to the Include statement on line 523:
Alias /bitnami/ "/Applications/XAMPP/xamppfiles/apache2/htdocs/" Alias /bitnami "/Applications/XAMPP/xamppfiles/apache2/htdocs" <Directory "/Applications/XAMPP/xamppfiles/apache2/htdocs"> Options Indexes FollowSymLinks AllowOverride All Order allow,deny Allow from all </Directory>
On lines 1 and 2 the Alias directive is used to map a URL containing /bitnami/ or /bitnami to /Applications/XAMPP/xamppfiles/apache2/htdocs/ or /Applications/XAMPP/xamppfiles/apache2/htdocs respectively, allowing Apache to serve files outside of the DocumentRoot. As such, a request to localhost/bitnami should cause Apache to serve /Applications/XAMPP/xamppfiles/apache2/htdocs/index.html.
However out-of-the box, a request to localhost/bitnami results in a 403 Forbidden error:
To understand why this is happening let’s take a look at another section of the Apache configuration file /Applications/XAMPP/xamppfiles/etc/htppd.conf:
# # Deny access to the entirety of your server's filesystem. You must # explicitly permit access to web content directories in other # <Directory> blocks below. # <Directory /> AllowOverride none Require all denied </Directory>
Using Require all denied, access to the server’s entire filesystem is forbidden and only granted to named directories if explicitly given. As an example, Require all granted explicitly grants access to /Applications/XAMPP/xamppfiles/htdocs as part of the Directory block on line 259 of /Applications/XAMPP/xamppfiles/etc/htppd.conf.
<Directory "/Applications/XAMPP/xamppfiles/htdocs"> # # Possible values for the Options directive are "None", "All", # or any combination of: # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews # # Note that "MultiViews" must be named *explicitly* --- "Options All" # doesn't give it to you. # # The Options directive is both complicated and important. Please see # http://httpd.apache.org/docs/trunk/mod/core.html#options # for more information. # #Options Indexes FollowSymLinks # XAMPP Options Indexes FollowSymLinks ExecCGI Includes # # AllowOverride controls what directives may be placed in .htaccess files. # It can be "All", "None", or any combination of the keywords: # Options FileInfo AuthConfig Limit # #AllowOverride None # since XAMPP 1.4: AllowOverride All # # Controls who can get stuff from this server. # Require all granted </Directory>
However, if we look again at /Applications/XAMPP/xamppfiles/apache2/conf/httpd.conf there is no Require all granted. Instead we see Order allow,deny and Allow from all:
Alias /bitnami/ "/Applications/XAMPP/xamppfiles/apache2/htdocs/" Alias /bitnami "/Applications/XAMPP/xamppfiles/apache2/htdocs" <Directory "/Applications/XAMPP/xamppfiles/apache2/htdocs"> Options Indexes FollowSymLinks AllowOverride All Order allow,deny Allow from all </Directory>
The Order and Allow directives are provided by Apache’s mod_access_compat module and as of Apache v2.4 have been deprecated in favour of the Require directive provided by the mod_authz_host module. Both of these modules are loaded by XAMPP so either Order allow,deny together with Allow from all or Require all granted by itself should work, but the Apache documentation states:
Mixing old directives like Order, Allow or Deny with new ones like Require is technically possible but discouraged. mod_access_compat was created to support configurations containing only old directives to facilitate the 2.4 upgrade. Please check the examples below to get a better idea about issues that might arise.
Let’s replace the Order and Allow directives with a single Require directive:
Alias /bitnami/ "/Applications/XAMPP/xamppfiles/apache2/htdocs/" Alias /bitnami "/Applications/XAMPP/xamppfiles/apache2/htdocs" <Directory "/Applications/XAMPP/xamppfiles/apache2/htdocs"> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory>
A request to localhost/bitnami/ now serves the following page:
As an alternative, we can map a new URL to a new location by adding the configuration to the existing /Applications/XAMPP/xamppfiles/apache2/conf/httpd.conf file:
Alias /bitnami/ "/Applications/XAMPP/xamppfiles/apache2/htdocs/" Alias /bitnami "/Applications/XAMPP/xamppfiles/apache2/htdocs" <Directory "/Applications/XAMPP/xamppfiles/apache2/htdocs"> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> Alias /steve/ "/Users/steve/Sites/myblog/" Alias /steve "/Users/steve/Sites/myblog" <Directory "/Users/steve/Sites/myblog"> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory>
A request to localhost/steve/ serves the following page:
Whenever changes are made to Apache’s configuration files the Apache server has to be re-started1 for the changes to take effect. You can start, stop and restart the Apache server using the Manage Servers tab of XAMPP‘s Application Manager:
If you prefer, the Apache server can be managed from the command line in Terminal.
To stop the Apache server type:
sudo /Applications/XAMPP/xamppfiles/bin/apachectl stop
To start the Apache server type:
sudo /Applications/XAMPP/xamppfiles/bin/apachectl start
To re-start1 the Apache server type:
sudo /Applications/XAMPP/xamppfiles/bin/apachectl graceful
1 If the Apache server is running, apachectl graceful doesn’t first stop and then start the server, it simply reloads the configuration files. If the Apache server is not running, apachectl graceful attempts to start it.
Well explained article Steve!
I’ve followed your article and changed the DocumentFolder in /Applications/XAMPP/xamppfiles/etc/httpd.conf to /Users/rey/Sites/mysite and added the alias and directory directive in /Applications/XAMPP/xamppfiles/apache2/conf/httpd.conf; however, I’m still getting Access forbidden error. Do I need to change the directory settings for the folder in Mac Finder?
Hi Rey,
I’m getting the same access forbidden error when trying to serve files from my home directory. Apache’s error log says [client ::1:49694] AH00035: access to /steve denied (filesystem path ‘/Users/steve/Sites’) because search permissions are missing on a component of the path. You can check the error log using XAMPP’s Application Manager > Manage Servers > Apache Web Server > Configure > Open Error Log.
If you look at /Applications/XAMPP/xamppfiles/etc/httpd.conf on line 173-174, both the User and Group are set to daemon. The daemon user doesn’t have access to your home directory, hence the access forbidden error. If you change just the User to rey, leaving the Group as daemon it should work.
Further reading https://cwiki.apache.org/confluence/display/httpd/13PermissionDenied and https://askubuntu.com/questions/451922/apache-access-denied-because-search-permissions-are-missing.
Hope this helps.
Regards, Steve.
It is a beautiful article!
And thank you so much 🙂
Thank you so much Steve. I was having hard time for like last 5 hours figuring this XAMPP thing out and your tutorial really helped me to sort my issue out.
Big thanks from a struggling programmer 🥹🥹
Glad you found it useful Gagan.
Thanks for the explanation! It is really helpful for me!
yes, found helpful. Thanks