Curing ‘Symbolic link not allowed’ (Apache 2.0)

Awhile back when trying to add a directory to Apache on my Ubuntu 6.06 LTS server, I ran into some issues. These issues, of course were the infamous 403 “Forbidden” error that your web barfs up when you try to access a server that is not publicly viewable, because of permission issues. I’m going to give you my scenario and explain how you can fix this issue, so that you don’t have to go through an hour of throwing your hands up in disgust.

The Scenario

In our example, out DocumentRoot (where all the HTML files are stored on the server) is /var/www/. This is the default on most Linux servers and can be a constant fuss when you don’t have that big of a partition for the /var directory. Things that can be done to prevent this is:

  • When installing the OS, add the /var mount-point to a larger disk/partition.
  • Add a new (larger) disk to the system, format it accordingly, migrate the old /var/ mount-point to the new partition and change the DocumentRoot in the Apache configuration. This requires backing up old files and pushing them to the new partition and reconfiguring a small part of Apache; could cause a lot of downtime.
  • Use symbolic links within the DocumentRoot.

As the shade of green emphasizes, we will be using symbolic links. Of course, this should be a very easy task, but can easily become a hassle to get working. Also note that we could have used the other choices above, but I chose the best solution to this problem. I’ll discuss how to set it up, and then I’ll explain how to fix the “Symbolic link not allowed” error found in your Apache error logs when you get the 403 error in your web browser.

Setting It All Up

To give you an idea of what has to be done, we will setup the symbolic links (which I will now refer to as symlinks) and make sure they point to the right directory and actually work. Then we will need to make the adjustments in the Apache configuration file so that the server will accept the symlinks; this will require an Apache restart, which really doesn’t create downtime for the user, unless something goes wrong. If all goes well, this is great. If you aren’t lucky enough to get it the first try, it probably isn’t your fault entirely, and I’ve got you covered with something that led me to the fix. Just a little sidenote, when I say fix, I don’t mean that there’s a bug in the system, I mean that we will resolve a very small issue that is often overlooked. Alright, now on with the good stuff!

Creating The Symlinks

First off, what is a symlink? A symlink is a special type of file, usually found in Unix, which refers to another file by its pathname. So in laymen terms, a symlink is a folder that is redirected to another folder on a Unix system. To those people that argue about my statement about Linux, I know symlinks can also be used in Windows, but that is another article to be written and is totally different from the Unix side.

Okay, so how do we set that symlink setup? This is extremely easy; we just need a few basic commands to get this done. The only thing we have to make sure of is that the destination target actually exists. After we create (or just make sure that the destination target exists) we create the symlink and then make sure it has become a symlink, which can easily be noticed by color or listing, which depends on your system. So, let’s create the destination directory (if needed):

BASH

mkdir /data/www/newdirectory

After the mkdir command you type in where you want your destination target to be at. This is just a folder that you will put regular files such as .html, .css, .php into; web content. I chose /data/www/newdirectory, but you should choose whatever you want. Remember, this is an if-needed basis. If you already know what you are wanting to create a symlink to and you are just wanting to create the symlink to the destination target keep on reading. Alright, now let’s create the symlink. If your DocumentRoot is the default /var/www/, you will want to create your symlink there. If you do not actually know your DocumentRoot is try running one of the following lines:

BASH

cat /etc/apache2/sites-enabled/000-default | grep "DocumentRoot"
cat /etc/httpd/conf/httpd.conf | grep "DocumentRoot"

This should actually output the DocumentRoot target. So, for simplicity sake, we will say that your DocumentRoot is located in /var/www/; this is the most commonly known default DocumentRoot. So, once in that directory we need to actually create the symlink:

BASH

cd /var/www/
ln -s /data/www/newdirectory/ mysymlink

The ln command stands for link and the -s makes it a symbolic (soft) link. It is alot safer to do a symbolic link rather than a hard link; if you delete a hard link, you also delete the actual files, not just the link. So how do you know if your symlink was actually created successfully. A simple ls command should do the trick:

BASH

ls

To find out if the symlink was a success, in our example, go to /var/www/ and type in:

BASH

ls -l /var/www/

You should then see something like this:

BASH Output

lrwxrwxrwx 1 ftpuser  ftp        21 2006-09-13 16:37 mysymlink -> /data/www/newdirectory/

You can also do an ls -l of the symlink, as you normally would a regular directory and you should see all the files as if they were in your /var/www/ directory, even though they are actually in /data/www/newdirectory/. If all goes well, then we have successfully setup our symlink. Now we have to configure Apache to allow these symlinks to work.

Editing Apache 2.0 Configuration File

In Debian systems such as Ubuntu, I have noticed that Apache uses the sites-enabled configuration. This means you must edit the sites within this directory for the changes to be effective. For other systems such as Red Hat you must edit the /etc/httpd/conf/httpd.conf. The default site in Ubuntu is 000-default, so when editing this file and your server is not using the sites-enabled configuration, Red Hat or any other users should probably edit /etc/httpd/conf/httpd.conf. If you have any issues with this, please let me know so I can update this article with additional details on how to do it for particular systems.

Let’s take a look at /etc/apache2/sites-enabled/000-default and add the correct configuration changes to allow for our symlinks to be used. You should add the following to your <directory /var/www/> directive:

Apache Site Configuration

Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all

Now, restart Apache:

BASH

/etc/init.d/apache2 restart      # Debian/Ubuntu
service httpd restart              # Red Hat (easy)
/etc/init.d/httpd restart          # Red Hat (preferred)

Now that’s complete, you should now be able to access this, using our example by pointing your browser to http://yourdomain.com/mysymlink/. Did it work? If so, great! If not, let’s fix it!

Resolving the permission issues

To resolve this issue, more than likely, it is no longer an Apache issue anymore, as we have correctly configured Apache for SymLinks. More than likely, the cause of this issue is due to permissions on the filesystem. I’m going to stick with the example used here so that I don’t confuse anyone. We have been symlinking to the directory /data/www/newdirectory/. First off, make sure the files in the directory that you are symlinking are assigned to the group www-data (or whatever your Apache user’s group is) and make sure that they have read/execute permissions. If this does not resolve the issue, then it’s a little deeper than just a file, which is usually the case.

If you were symlinking the /data/www/newdirectory/, then the /data, /data/www, and the /data/www/newdirectory directories must have at least read access, so that Apache user can access the directory (we will be using the Apache group to share). To resolve this issue, first find out the Apache group is:

BASH

[root@tangerine ~]# cat /etc/httpd/conf/httpd.conf | grep ^Group
Group apache

In Red Hat, the Apache’s group is apache, but if you are using Ubuntu or Debian Linux, the Apache group is usually www-data. In this case, we need to make sure the apache group has read/execute access to the /data, /data/www, and /data/www/newdirectory directories. To do this, you would run the following command:

BASH

# Execute for Red Hat
chmod -R 755 /data/www/newdirectory/ && chown -R :apache /data/www/newdirectory/ 

# Execute only if using Debian or Ubuntu systems
chmod -R 755 /data/www/newdirectory/ && chown -R :apache /data/www/newdirectory/ 

You should not have to restart Apache for the setting to take effect, as this is only permissions on the filesystem. Go back to your web browser and try to refresh the page or bring the page up if you closed your web browser and see if you still get the insufficient privileges error message. If not, great! This had me stumped for the longest time, until I realized sometimes it’s the most obvious things that are the problems. If this didn’t help you to get things working, let me know and let’s try to get it sorted.


Discussion always soothes thy heart.

1 Quote this comment

Minor detail, but when you say,

“If you were symlinking the /data/www/newdirectory/, then the /data, /data/www, and the /data/www/newdirectory directories must have at least read access, so that Apache user can access the directory (we will be using the Apache group to share)”

Actually, all you need is execute permissions for the parent directories, so apache can open files within the folder. Not having a read permissions on the directory prevents a user(including apache) from listing the directory’s contents. If the location name is known(as in the case of a symlink), a user can cd to it without read permissions on parent directories. You will want read permission on the directory that you are symlinking though.

2 Quote this comment

DOH! didin’t realise that the parent dir permissions were important… been hunting around for hours for a solution to this … THANK YOU

By: luke

3 Quote this comment

DOH! didin’t realise that the parent dir permissions were important… been hunting around for hours for a solution to this … THANK YOU

Awesome! You are very welcome. This was my main issue, too, when I was trying to do this for the first time, thus why I documented it. Glad it helped you.

Thanks,
Drew

By: Drew

4 Quote this comment

I’ve done everything – at least I think so – what you have suggested, but symlinking is still not working.
The parts of the http.con-File connected to linking are set like this:


DocumentRoot "/var/www/html"
Options FollowSymLinks
Options FollowSymLinks
AllowOverride None
Options FollowSymLinks
Options Indexes FollowSymLinks

But I still get the error message in /var/log/http/error_log:
Directory index forbidden by Options directive:

I will be thankful for a hint, what might be still wrong!

By: bernd

5 Quote this comment

Bernd,

You have three Options FollowSymLinks options in your code. Make sure you only have one.

That is just something you should do. However, the error message you are receiving is due to not having an index page in your directory (the one that is symlinked). In order to have Directory Listing is to add a line in your directive, like so:

Options Indexes

Please let me know if you have any questions.

Regards,
Drew

By: Drew

6 Quote this comment

I?ve done everything what you have suggested, but i still get the error message shown below:
Forbidden
You don’t have permission to access /cgi-bin/jha.cgi on this server.
Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument to handle the request.
Apache/2.0.52 (Red Hat) Server at rhino.sbcld.sbc.com Port 80
Below is the soft link i created under /var/www/cgi-bin/
jha.cgi -> /home/emasld/EMAS_WEB_PROD/app/jha.cgi

By: Janet

7 Quote this comment

Janet,

I believe CGI is handled differently. Have you tried a test file in a different directory (a non CGI-BIN directory), just to make sure the permissions were right? I would check this first before you mess around with the CGI directories, because I believe there is additional configuration for the CGI-BIN directory, for Apache.

Regards,
Drew

By: Drew

8 Quote this comment

i tried one htm file(test.htm) in /var/www/html directory and it is working without any problems. I also tried one test file(test.cgi) that doesn’t have any soft links associated with in /var/www/cgi-bin directory and it is working fine. Below is my cgi-bin configuration from httpd.conf : 545 ScriptAlias /cgi-bin/ “/var/www/cgi-bin/”
546
547 #
548 # “/var/www/cgi-bin” should be changed to whatever your ScriptAliased
549 # CGI directory exists, if you have that configured.
550 #
551
552 AllowOverride None
553 Options All
554 Order allow,deny
555 Allow from all
556

By: Janet

9 Quote this comment

551
552 AllowOverride None
553 Options All
554 Order allow,deny
555 Allow from all
556

By: Janet

10 Quote this comment

sorry line 551 should be
and line 556 should be

By: Janet

11 Quote this comment

I had the same situation described here with a RHEL installation. I thought I had all permissions correct, but still the same Forbidden error. I followed the comments here and did a chown to apache, but still the problem!
After some more searching we found about SELinux causing havoc like this. We turned this off issuing “echo 0 > /selinux/enforce” and all is working. I haven’t done more research to see how you can have this ON while still getting the above working, but for those out there who just need to get it going give this a try.

By: Jose

12 Quote this comment

THANK YOU Jose. It works fine after i did echo 0 > /selinux/enforce

By: Janet

13 Quote this comment

Basically make it even more clear that you just need issue below
#chmod -R 755 /data
#chmod -R 755 /data/www
#chmod -R 755 /data/www/newdirectory

for you SElinux, you can run
#getsebool -aef|Grep httpd

to check the if it block it.
However, THANK YOU SO MUCH for this documentation.

By: Peter

14 Quote this comment

Guys (and Gal),

Thanks for the feedback. Of course you can disable SELinux, or just set the correct permissions for SELinux to work nicely with Apache. Keep up the comments!

Regards,
Drew

By: Drew

15 Quote this comment

qw(Add a new (larger) disk to the system, format it accordingly, migrate the old /var/ mount-point to the new partition and change the DocumentRoot in the Apache configuration. This requires backing up old files and pushing them to the new partition and reconfiguring a small part of Apache; could cause a lot of downtime.)

If you have the luxury of being able to add a seprate partion to the system it’s actually way easier than this and doesn’t require reconfiguring apache.

add the new partition to the system (however you are going to do that based on your hardware)
mount it temporarily at something like /mnt/myNewDisk or just /mnt (see man mount)
*Take a backup*
move all the files from /var/www (or whatever your web dir is.
mv /var/www/* /mnt/myNewDisk/
unmount said new disk
umount /mnt/myNewDisk
remount it on the now empty /var/www/ which makes a great mount point
edit your fstab (or vfstab) file to ensure this mounts at startup.

I’m leaving out details on things like mount and fstab because they are a little os/vendor/filesystem specific. Generally they are pretty similar but you may need to brush up on the man page. In a pinch the /etc/fstab or /etc/vfstab can give you the options that you need but you’ll have to double check your syntax for the command line.

By: Aaron

16 Quote this comment

Setting every directory to executable all the way down from the root to the directory I was linking to did the trick for me. THANK YOU VERY MUCH!!!

By: dean

17 Quote this comment

Hi,
I’m having the same problem. I have my DocumentRoot directory on the local filesystem. However, I cannot follow the links! My DocumentRoot is /web and here is the permission for it:

drwxrwxrwx 3 root apache 4096 Jul 17 11:09 /web

In /web directory I have a symlink:
lrwxrwxrwx 1 root root 31 Jul 16 17:00 /web/habib.html -> /home/habib/web/habib.html

Permissions for /web (DocumentRoot) and other directories:


drwxrwxrwx 3 root       root        0 Jul 17 10:33 /home
drwxrwxrwx 2 habib groupa 64 Jul 17 10:58 /home/habib
drwxrwxrwx 2 habib groupa 64 Jul 16 17:04 /home/habib/web
-rwxrwxrwx 1 nfsnobody  nfsnobody  69 Jul 16 16:57 /home/habib/web/habib.html

As you can see, I have read, write and execute permissions on all files and directories.

And here is from my httpd.conf:


User apache
Group apache

Options FollowSymLinks
AllowOverride None

Options Indexes FollowSymLinks
AllowOverride None

Order allow,deny
Allow from all

Would you help me please?

Thanks.

By: Habib

18 Quote this comment

Habib,

What does your error logs for Apache say? Usually you can find out what the error logs are telling you and do a simple search on the error on Google, and figure it out pretty fast. Let me know if you still need some help.

By: Drew

Go ahead, say somethin'

Note: If this is your first time commenting on my site, there will be a delay, as I have to approve your comment.