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:
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/
To know which user you are logged on to:
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)
Change the www folder and make it belong to varwwwusers
www-data is the server making django requests, add that to the group
Change folder policy
Add ubuntu to the group of varwwwusers
Hope this helps!
I had a similar issue in Django 1.10, and this page was the first google result, but the accepted solution did not solve my problem. With a 'MEDIA' directory located in the root of your project for storing files, you just needed to set:
MEDIA_ROOT = os.path.join(BASE_DIR,'MEDIA')
and then I stopped getting the error. I had been trying a number of variations before I found that this worked.
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 usingwww-data
's privileges.www-data
is neither the owner nor in the group of users that own/var/www
. This means thatwww-data
is treated asother
and has the permissions set to others.The BAD solution to this would be to do:
This would give everyone full access to everything in
/var/www/
, which is a very bad idea.Another BAD solution would be to do:
This would change the owner to
www-data
, which opens security vulnerabilities.The GOOD solution would be:
This adds
www-data
to thevarwwwusers
group, which is then set as the group for/var/www/
and all of its subfolders.chmod
will give read, write, execute permissions to the owner but the group will not be able to execute any script potentially uploaded in there if for example the webserver got hacked.You could set it to
740
to make it more secure but then you won't be able to useDjango's
collectstatic
functionality so stick to760
unless you're very confident about what you're doing.