[apache] Apache won't follow symlinks (403 Forbidden)

I'm having some trouble setting up Apache on Ubuntu. I've been following this guide.

# /usr/sbin/apache2 -v
Server version: Apache/2.2.17 (Ubuntu)
Server built:   Feb 22 2011 18:33:02

My public directory, /var/www, can successfully serve up and execute PHP pages that are placed in it. However, I want to create a symlink in /var/www that points to a directory in my home folder and serve pages there.

[root /var/www]# ll
total 36
drwxr-xr-x  3 root root 4096 2011-09-11 14:22 .
drwxr-xr-x 14 root root 4096 2011-06-04 22:49 ..
lrwxrwxrwx  1 root root   16 2011-09-11 13:21 about -> /root/site/about

When I try to access /about on browser, I get

Forbidden

You don't have permission to access /about on this server.

As far as I know, I gave sufficient privileges to the files I want to serve:

[root ~/site/about]# ll
total 24
drwxr-xr-x 5 root root 4096 2011-09-11 13:20 .
drwxr--r-- 3 root root 4096 2011-09-11 13:19 ..
drwxr-xr-x 2 root root 4096 2011-09-11 13:21 contact
-rwxr-xr-x 1 root root 1090 2011-09-11 13:19 index.php
drwxr-xr-x 2 root root 4096 2011-09-11 13:20 me
drwxr-xr-x 2 root root 4096 2011-09-11 13:21 resume

I'm aware of the FollowSymLinks option, and I believe it's set in my /etc/apache2/sites-enabled/000-default file:

DocumentRoot /var/www
<Directory />
    Options FollowSymLinks
    AllowOverride None
</Directory>
<Directory /var/www/>
    Options FollowSymLinks Indexes MultiViews
    AllowOverride None
    Order allow,deny
    allow from all
</Directory>

Any idea what I could be missing?

This question is related to apache configuration apache2 symlink

The answer is


With the option FollowSymLinks enabled:

$ rg "FollowSymLinks" /etc/httpd/
/etc/httpd/conf/httpd.conf
269:    Options Indexes FollowSymLinks

you need all the directories in symlink to be executable by the user httpd is using.

so for this general use case:

cd /path/to/your/web
sudo ln -s $PWD /srv/http/

You can check owner an permissions with namei:

$ namei -m /srv/http/web
f: /srv/http/web
 drwxr-xr-x /
 drwxr-xr-x srv
 drwxr-xr-x http
 lrwxrwxrwx web -> /path/to/your/web
   drwxr-xr-x /
   drwxr-xr-x path
   drwx------ to
   drwxr-xr-x your
   drwxr-xr-x web

In my case to directory was only executable for my user:

Enable execution by others solve it:

chmod o+x /path/to

See the non executable directory could be different, or you need to affect groups instead others, that depends on your case.


There is another way that symbolic links may fail you, as I discovered in my situation. If you have an SELinux system as the server and the symbolic links point to an NFS-mounted folder (other file systems may yield similar symptoms), httpd may see the wrong contexts and refuse to serve the contents of the target folders.

In my case the SELinux context of /var/www/html (which you can obtain with ls -Z) is unconfined_u:object_r:httpd_sys_content_t:s0. The symbolic links in /var/www/html will have the same context, but their target's context, being an NFS-mounted folder, are system_u:object_r:nfs_t:s0.

The solution is to add fscontext=unconfined_u:object_r:httpd_sys_content_t:s0 to the mount options (e.g. # mount -t nfs -o v3,fscontext=unconfined_u:object_r:httpd_sys_content_t:s0 <IP address>:/<server path> /<mount point>). rootcontext is irrelevant and defcontext is rejected by NFS. I did not try context by itself.


The 403 error may also be caused by an encrypted file system, e.g. a symlink to an encrypted home folder.

If your symlink points into the encrypted folder, the apache user (e.g. www-data) cannot access the contents, even if apache and file/folder permissions are set correctly. Access of the www-data user can be tested with such a call:

sudo -u www-data ls -l /var/www/html/<your symlink>/

There are workarounds/solutions to this, e.g. adding the www-data user to your private group (exposes the encrypted data to the web user) or by setting up an unencrypted rsynced folder (probably rather secure). I for myself will probably go for an rsync solution during development.

https://askubuntu.com/questions/633625/public-folder-in-an-encrypted-home-directory

A convenient tool for my purposes is lsyncd. This allows me to work directly in my encrypted home folder and being able to see changes almost instantly in the apache web page. The synchronization is triggered by changes in the file system, calling an rsync. As I'm only working on rather small web pages and scripts, the syncing is very fast. I decided to use a short delay of 1 second before the rsync is started, even though it is possible to set a delay of 0 seconds.

Installing lsyncd (in Ubuntu):

sudo apt-get install lsyncd

Starting the background service:

lsyncd -delay 1 -rsync /home/<me>/<work folder>/ /var/www/html/<web folder>/

First disable selinux (vim /etc/selinux/config)

vim /etc/httpd/conf/httpd.conf edit following lines for symlinks and directory indexing:

documentroot /var/www/html
<directory /var/www/html>
    Options Indexes FollowSymLinks
    AllowOverride None
</directory>

If .htaccess file then AllowOverride all


In addition to changing the permissions as the other answers have indicated, I had to restart apache for it to take effect:

sudo service apache2 restart

For anyone having trouble after upgrading to 14.04 https://askubuntu.com/questions/452042/why-is-my-apache-not-working-after-upgrading-to-ubuntu-14-04 as root changed before upgrade = /var/www after upgrade = /var/www/html


I was having a similar problem that I could not resolve for a long time on my new server. In addition to palacsint's answer, a good question to ask is: are you using Apache 2.4? In Apache 2.4 there is a different mechanism for setting the permissions that do not work when done using the above configuration, so I used the solution explained in this blog post.

Basically, what I needed to do was convert my config file from:

Alias /demo /usr/demo/html

<Directory "/usr/demo/html">
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    allow from all

</Directory>

to:

Alias /demo /usr/demo/html

<Directory "/usr/demo/html">
    Options FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

Note how the Order and allow lines have been replaced by Require all granted


Yet another subtle pitfall, in case you need AllowOverride All:

Somewhere deep in the fs tree, an old .htaccess having

    Options Indexes

instead of

    Options +Indexes

was all it took to nonchalantly disable the FollowSymLinks set in the server config, and cause a mysterious 403 here.


Related to this question, I just figured out why my vhost was giving me that 403.

I had tested ALL possibilities on this question and others without luck. It almost drives me mad.

I am setting up a server with releases deployment similar to Capistrano way through symlinks and when I tried to access the DocRoot folder (which is now a symlink to current release folder) it gave me the 403.

My vhost is:

DocumentRoot /var/www/site.com/html
<Directory /var/www/site.com/html>
        AllowOverride All
        Options +FollowSymLinks
        Require all granted
</Directory>

and my main httpd.conf file was (default Apache 2.4 install):

DocumentRoot "/var/www"
<Directory "/var/www">
    Options -Indexes -FollowSymLinks -Includes
(...)

It turns out that the main Options definition was taking precedence over my vhosts fiel (for me that is counter intuitive). So I've changed it to:

DocumentRoot "/var/www"
<Directory "/var/www">
    Options -Indexes +FollowSymLinks -Includes
(...)

and Eureka! (note the plus sign before FollowSymLinks in MAIN httpd.conf file. Hope this help some other lost soul.


Examples related to apache

Enable PHP Apache2 Switch php versions on commandline ubuntu 16.04 Laravel: PDOException: could not find driver How to deploy a React App on Apache web server Apache POI error loading XSSFWorkbook class How to enable directory listing in apache web server Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details How to enable php7 module in apache? java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient The program can't start because api-ms-win-crt-runtime-l1-1-0.dll is missing while starting Apache server on my computer

Examples related to configuration

My eclipse won't open, i download the bundle pack it keeps saying error log Getting value from appsettings.json in .net core pgadmin4 : postgresql application server could not be contacted. ASP.NET Core configuration for .NET Core console application Turning off eslint rule for a specific file PHP Warning: Module already loaded in Unknown on line 0 How to read AppSettings values from a .json file in ASP.NET Core How to store Configuration file and read it using React Hadoop cluster setup - java.net.ConnectException: Connection refused Maven Jacoco Configuration - Exclude classes/packages from report not working

Examples related to apache2

Only variable references should be returned by reference - Codeigniter 413 Request Entity Too Large - File Upload Issue Site does not exist error for a2ensite How to convert .pem into .key? Apache: Restrict access to specific source IP inside virtual host CodeIgniter removing index.php from url Failed Apache2 start, no error log Apache2: 'AH01630: client denied by server configuration' what does it mean "(include_path='.:/usr/share/pear:/usr/share/php')"? How to check is Apache2 is stopped in Ubuntu? Nginx sites-enabled, sites-available: Cannot create soft-link between config files in Ubuntu 12.04 How to see full absolute path of a symlink Create a symbolic link of directory in Ubuntu How do I find all of the symlinks in a directory tree? Apache won't follow symlinks (403 Forbidden) Git Symlinks in Windows How to check if a symlink exists How can I symlink a file in Linux? Can you change what a symlink points to after it is created? How does Git handle symbolic links?