Django - Serving MEDIA/uploaded files in production - python

I currently have this in my project urls.py, the last line is what's important.
urlpatterns = patterns('',
url(r'^', include('polls.urls', namespace="polls")),
url(r'^admin/', include(admin.site.urls)),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I've been told and I've read that this is not suitable for a production environment. Why is this the case?

Django is built to be an "application server", not a "web server".
In other words, serving static files from Django will have worse performance than using Apache or Nginx. These static content servers are (1) written in C and (2) optimized for performance.
In contrast, Django is (1) written in pure Python and (2) optimized for developing an application.
See the documentation.
That may be totally fine. I have used Django to serve static content in production, when I knew the load would not be high and I wasn't serving large files. It depends on what kind of environment "production" actually is.
FYI, A common production setup would be to use Nignx, Django, Gunicorn, and Supervisor. Nginx servers the static content from disk and reverse proxies the rest of it to Gunicorn, which runs multiple Django instances. Supervisor monitors Gunicorn and makes sure it stays running. It all depends on what level of web application you need.

It is not recommended to serve static files from the django server itself. The recommended way is to serve them in a separate server. check static files deployment, there you will find all you need.

Extending #Paul Draper's answer:
When using Nginx, make sure to list the following configuration:
location /media/ {
root path/to/your/media;
}

I used the tutorial for the google section of the django-storages package and it solves the issue serving the files (either static or media or both) from Google Storage, which avoids the trouble of additional configuration on Nginx or the like

Related

How to deploy Django project using FTP or cPanel on Hostgator

I've built a Django project with Python and a MySQL database. I'm ready to deploy it to a shared server hosting platform called Hostgator. Their tech support tells me to load all my project files directly into a public_html directory, but when I do that, and navigate to my domain, I just see a list of files (see below), instead of the website I built. What am I missing?
I can't find any good documentation for this kind of deployment. I've done the Django deploy checklist and I think I have that stuff done right. I'm wondering about if/what to put in an .htaccess file, and I'm also not sure how to configure my STATIC_URL or STATIC_ROOT. Do I need to update those to have the path of my production domain? I have run the collectstatic command on the project.
As of now, I have the following for my static file handling in settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
You don't want your django app in public_html. If you are using nginx or apache (you are using one of them, probably visible in the lower left of your screenshot just out of crop range), you likely want to proxy to the process running your Django app (gunicorn is one way to do that).
Essentially, Nginx handles all the web traffic, and hands off (via proxy) anything for your Django app to Gunicorn which is running your wsgi application (Django). Nginx can also then serve up your static files as well.
Digital ocean has a decent 'how to' that covers most of it in depth.
https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04

An easy way to show images in Django on deployment (DEBUG=false)

I am using DJango 1.8 and python 3.4.3, and I have been running my app on Debug mode, and found a way to show images inside a directory configured on MEDIA_ROOT, this was my first question and the solution I have found: How to upload and show images in DJango. But reading the docs I found that that solution is not suitable for a served app, so, if I stop using "Debug=True" the images will not be displayed, and I have to use one of the options exposed on this link: Static files on deployment but I don't have money to pay another server, I just can pay my hosting on pythonanywhere, and for the option to use the same server for the images, I don't have idea how to automate the collectstatic and also don't know how to trigger it when an user uploads a new image.
I have used ASP.NET and PHP5 and I didn't had problems with the images in none of them, so, I have two questions:
Is there an easy way to show images URL's?
Is there a high risk security problem if I deploy my app with DEBUG=True?
I hope you can help me, because I find this ridiculous, probably is for better security, but it just not make sense for a framework, instead of making the work easier it make it more difficult and stressful.
Django runserver is not intended for serving up static files in a production environment. It should be limited to development and testing environments.
If you are intending to use django's runserver to server up static files with DEBUG=False then use the --insecure flag.
You should never deploy a site with DEBUG = True due to security implications.
Static files and media assets are 2 different things.
Static Files
Static files are things like images you created and files that come with 3rd party apps you have installed (e.g. django-cms). These files include images, css and javascript files etc.). So you need to have a settings.STATIC_ROOT for this.
python manage.py collectstatic collects static files from different locations and puts them all in a single folder.
Media Files
Media files are things the user uploads (e.g. photos, documents etc.). So you have a settings.MEDIA_ROOT for this. collecstatic won't do anything to media files, they will just be there already once the user uploads them.
Serving up static and media files in production
Frameworks like Django aren't going to cover automatic production server configuration - that is something else you will have to learn unfortunately.
There are a lot of good guides around e.g. this one to help you get started serving media and static files in production.
Regarding server costs, I'm sure you can find a host to give you some free credit, or pay $5/month for a server somewhere... try lowendbox
Here is a guide from pythonanywhere regarding media and static files: https://help.pythonanywhere.com/pages/DjangoStaticFiles/
1) in urls.py add:
(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
and open url http://myhost.com/media/
2) Never deploy a site into production with DEBUG turned on, DEBUG=True is a security issue,

Why not serving static files with Django in a production environment?

I came across the following example for settings.py:
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
and was told:
The static() helper function is suitable for development but not for
production use. Never serve your static files with Django in a
production environment.
Can anyone explain why and how to use it the better way?
EDIT:
Can I use static() with Apache?
Django is not very fast or efficient for serving static files. To quote the Django docs, "This method is grossly inefficient and probably insecure, so it is unsuitable for production." It is better to use tools that are specifically designed for serving static content. There are extensive instructions for how to setup a static server in the Django documentation on deploying static files.
The basic idea is to not unnecessarily involve Django in the serving of static files. Let your production server, which from your comment it sounds like is apache, serve the static files directly. Here are instructions for editing your httpd.conf file to get apache to serve the static files https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/modwsgi/#serving-files. The static() function in django should not be involved at all. Make sure to use the collectstatic management command in django to copy all your static files to the STATIC_ROOT so apache can find them.

Hosting API docs generated with mkdocs at a URL within a Django project

I tend to write my API documentation in Markdown and generate a static site with MkDocs. However, the site I'd like to host the documentation on is a Django site. So my question is, and I can't seem to find an answer Googling around, is how would I go about hosting the MkDocs static generated site files at a location like /api/v1/docs and have the static site viewable at that URL?
UPDATE:
I should point out I do serve all static files under Apache and do NOT use runserver or Debug mode to serve static files, that's just crazy. The site is completely built and working along with a REST API.
My question was simply how do I get Django (or should I say Apache) to serve the static site (for my API docs) generated by MkDocs under a certain URL. I understand how to serve media and static files for the site, but not necessarily how to serve what MkDocs generates. It generates a completely static 'site' directory with HTML and assets files in it.
Django is just a framework you need to host your static files and serve them with something like Nginx or Apache etc.
I think you need the alias directive in apache and use that to redirect certain URLs to your static documentation site.
from the docs
urls = [
static(settings.STATIC_URL, document_root=settings.STATIC_ROOT),
("/home","views.home"),
...
]
https://docs.djangoproject.com/en/1.8/howto/static-files/#serving-static-files-during-development
in your request you would change to
static("/api/v0/docs",document_root="/home/docs/")

Can Django run on Gunicorn alone (no Apache or nginx)?

I have tried just about every django + nginx tutorial on the web and I cannot get an image file to display on the screen. It's always the old story - 404 PAGE NOT FOUND. The web page loads fine but django.png in my /static/ folder does not. Not sure if it's a problem in settings.py or with nginx.
I am so frustrated with it that I refuse to look at another "How to get nginx/django tutorial". If I deploy a website in the near future will Gunicorn suffice to run a Django site and serve static files simultaneously without using Apache or nginx? Is there a big benefit to having a reverse proxy in the first place?
Yes. Gunicorn can serve your static too.
If all else fails, let django do it for you (although, do this as a last resort before frustration.) To do that, you just have to add another url pattern, as follows:
urlpatterns = patterns('',
# ... the rest of your URLconf goes here ...
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
While django serving static is better than not serving it at all, it is worth delegating that to the servers optimized for the same like nginx.
I'd recommend running nginx on a different port to start with, and change the django STATIC_URL setting to include the port (After you have confirmed that the port serves the statics). - Doing this is as simple as doing a simlink to the MEDIA_ROOT from the nginx folder.
And if you are using nginx anyway, it is also good to proxy all requests using it and only pass the django request to the gunicorn. All this requires is the addition of a conf file that tells nginx accordingly.
I can see how it can be confusing to those who are starting and trying to do all (proxy requests, serve static, configure nginx) at once. Try it one by one. Get the media from the gunicorn; Then serve it from nginx and then eventually have the nginx proxy too. But do this all before you have your app in production. This approach, I have seen increases understanding and decreases frustration.
The Gunicorn documentation notes that without a proxy buffering slow clients, the default worker is susceptible to a denial of service attack: http://gunicorn.org/deploy.html
Although there are many HTTP proxies available, we strongly advise
that you use Nginx. If you choose another proxy server you need to
make sure that it buffers slow clients when you use default Gunicorn
workers. Without this buffering Gunicorn will be easily susceptible to
denial-of-service attacks. You can use slowloris to check if your
proxy is behaving properly.
This might not be the case when using one of the async workers such as gevent or tornado.
If you are already using amazon web services, you can use s3 buckets to host your static content and deploy your app to ec2 using gunicorn (or whatever you want). That way, you don't have to worry about setting up your own static file server at all.
I recommend using Nginx in front for several reasons:
Maintenance or internal server error page can be easily implemented when gunicorn is down. That means you will always have something to respond if your application server is not running.
As Gunicorn doc suggests, http attacks such as DOS are not detected.
You may want to implement your own load-balancing strategy later on. This will become more important for release engineering as your project scales. Personally, I've found AWS ELB a bit unreliable and I'm thinking about it.
Update:
Also, please see a well written answer by a Gunicorn developer:
Why do I need Nginx and something like Gunicorn?
I made by using a Werkzeug middleware. Is not beautiful, nor performant as using an nginx server, but does the job:
Set STATIC_ROOT on settings.py
# project/settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__)))
STATIC_ROOT = BASE_DIR+'/static-collected'
Than tell Werkzeug to serve files from this folder
# project/wsgi.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
(...)
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
(...)
import os
from werkzeug.wsgi import SharedDataMiddleware
print 'Installing WSGI static files server middleware'
application = SharedDataMiddleware(application, {
'/static': os.path.join(BASE_DIR, 'static-collected'),
})
When DEBUG=True, Django serve the files. When DEBUG=False, Werkzeug serve files from static-collected folder. You need to run collectstatic on the server that use DEBUG=False for this to work.
Obs: For some reason, Werkzeug gives 500 for not found files, not 404. Its weird, but still works. If you know why, please comment.

Categories

Resources