Django [Errno 13] Permission denied: '/var/www/media/animals/user_uploads'

Question:

I am developing a django API which will be running on top of Apache2 via WSGI on a server running Ubuntu.

Users will be able to upload pictures they take to the server using a POST request. The API processes this request and then attempts to write the image to /var/www/media/animals/user_uploads/<animal_type>/<picture_name>.jpg. In case there is no directory /var/www/media/animals/user_uploads/<animal_type>/ it will create it.

When testing during development everything was fine, both using Windows and Scientific Linux. When testing on the deployment server, I receive this error:

Django Error

From what I understand, the Apache2 server is running using the user www-data. In my case, running cat /etc/passwd to get the list of users, this is what I get for www-data:

www-data:x:33:33:www-data:/var/www:/bin/sh

I am assuming this means that www-data has access to everything in /var/www/. I have tried:

chmod 777 -R media

This worked but it is obviously a very bad way to solve this. Is there a better way to solve this?

This is my wsgi.py:

import os, sys
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "serengeti.settings")
sys.path.append('/serengeti/django/serengeti')
sys.path.append('/serengeti/django')

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

I have this in my settings.py file:

MEDIA_ROOT = '/var/www/media/'
MEDIA_URL = os.path.join(BASE_DIR,'/media/')

My vhost.conf contains this:

Alias /media/ /var/www/media/
Asked By: Vlad Schnakovszki

||

Answers:

I have solved this myself in the end.

When running on the development machines, I am in fact running using my current user’s privileges. However, when running on the deployment server, I am in fact running through wsgi, which means it’s running using www-data‘s privileges.

www-data is neither the owner nor in the group of users that own /var/www. This means that www-data is treated as other and has the permissions set to others.

The BAD solution to this would be to do:

sudo chmod -R 777 /var/www/

This would give everyone full access to everything in /var/www/, which is a very bad idea.

Another BAD solution would be to do:

sudo chown -R www-data /var/www/

This would change the owner to www-data, which opens security vulnerabilities.

The GOOD solution would be:

sudo groupadd varwwwusers
sudo adduser www-data varwwwusers
sudo chgrp -R varwwwusers /var/www/
sudo chmod -R 770 /var/www/

This adds www-data to the varwwwusers group, which is then set as the group for /var/www/ and all of its subfolders. You could set it to 750 to make it more secure but then you won’t be able to use Django's collectstatic functionality so stick to 770 unless you’re very confident about what you’re doing.

Answered By: Vlad Schnakovszki

To know which user you are logged on to:

$ whoami
ubuntu

And adding to your solution, if you are using an AWS Instance, you should add your user to the group to be able to access that folder:

Making a group for webservices users (varwwwusers)

$ sudo groupadd varwwwusers

Change the www folder and make it belong to varwwwusers

$ sudo chgrp -R varwwwusers /var/www/

www-data is the server making django requests, add that to the group

$ sudo adduser www-data varwwwusers

Change folder policy

$ sudo chmod -R 770 /var/www/

Add ubuntu to the group of varwwwusers

$ usermod -a -G varwwwusers ubuntu

Hope this helps!

Answered By: Abdulla AlKhenji

Create a ‘MEDIA’ directory in the root of your project.
Then set:

MEDIA_ROOT = os.path.join(BASE_DIR,'MEDIA')
Answered By: Nic Scozzaro

The resolution for this problem when dealing with the production server would be to make use of collectstatic as already mentioned that it used and resolved or give permissions to the folders. However if your solution is in a local environment, the solution can be acquired by configuring the local MEDIA directory in the settings.py file that acts on the local server.

So, would be adding these two lines in the local configuration file as @Nic Scozzaro mentioned:

MEDIA_ROOT = os.path.join (BASE_DIR, 'media')
STATIC_ROOT = os.path.join (BASE_DIR, 'static')

After the configuration restart the services to apply the fixes.

Answered By: Lucas Coelho

instead of :
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

add the following:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Answered By: Ali Abdelmalek

Unlike Others it was the answer for me (ubantu with gunicorn nginx)

instead of : MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

add the following: MEDIA_ROOT = os.path.join(BASE_DIR, '/media/')

Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.