16π
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.
14π
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.
- Appropriate choice of authentication class for python REST API used by web app
- How does this Man-In-The-Middle attack work?
- How to customize django rest auth password reset email content/template
- How to create custom groups in django from group
8π
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.
- Pycharm (Python IDE) doesn't auto complete Django modules
- How does django-nose differ from the default Django test-runner
- Django __call__() missing 1 required keyword-only argument: 'manager'
- How to unit test methods inside django's class based views?
- Celery β No module named five
7π
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:
2π
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.
- How to make follower-following system with django model
- How can I make a fixture out of QuerySet in django?
- Django ALLOWED_HOSTS with ELB HealthCheck