Django Media Files during production with nginx? - django

How can I serve media files during production?
Within nginx, I have:
upstream app_server {
server unix:/home/django/gunicorn.socket fail_timeout=0;
}
server {
# listen 80 default_server;
# listen [::]:80 default_server ipv6only=on;
listen 443 ssl;
server_name tweetz.co;
ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;
root /usr/share/nginx/html;
index index.html index.htm;
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
# Your Django project's media files - amend as required
location /media {
alias /home/django/django_project/django_project/media;
}
# your Django project's static files - amend as required
location /static {
alias /home/django/django_project/django_project/static;
}
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
# Your Django project's media files - amend as required
location /media {
alias /home/django/django_project/django_project/media;
}
# your Django project's static files - amend as required
location /static {
alias /home/django/django_project/django_project/static;
}
# Proxy the static assests for the Django Admin panel
location /static/admin {
alias /usr/lib/python2.7/dist-packages/django/contrib/admin/static/admin/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://app_server;
}
}
` `# Proxy the static assests for the Django Admin panel
location /static/admin {
alias /usr/lib/python2.7/dist-packages/django/contrib/admin/static/admin/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://app_server;
}
}
server{
listen 80;
server_name mywebsite.com;
return 301 https://$host$request_uri;
}
Not working. Do I need to change something else?
Below my files:
models.py
image = models.ImageField(upload_to='media',blank=True)
urls.py
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py
MEDIA_ROOT = '/home/django/django_project/static-serve/media/'
MEDIA_URL = '/media/'
server {
'/home/django/django_project/static-serve/media/image.jpg'
location /media {
autoindex on;
alias /home/django/django_project/static-serve/media/;
}
}
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
template
<img src="{{ object.profile.image.url }}" class="w3-circle" style="height:106px;width:106px" alt="Avatar">
The image source in the browser is: mysite/media/media/myimage.jpg
The image is saved: home/django/django_project/media/media/myimage.jpg
Thank you for any help

You should not prepend the path with a slash, since that means you want to upload your file to a directory named media in the root of your filesystem.
You can thus for example upload it to:
image = models.ImageField(upload_to='image/',blank=True)
If you however omit the upload_to=... parameter [Django-doc], Django will simply upload this to the MEDIA_ROOT [Django-doc].

Related

Django staticfiles not loading in AWS ec2

I've deployed a django webiste in AWS ec2 with the help of this digitalocean blog but the static files like css and javascripts are not loading after deployment.
This is my django static code:
STATIC_URL = '/static/'
MEDIA_URL = 'media/'
MEDIA_ROOT = 'media/'
STATIC_ROOT = 'staticfiles/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
and this is my nginx code:
server {
listen 80;
server_name mydomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /staticfiles/ {
root /home/sammy/project/myproject;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
And I'm using AWS S3 to host my static files.

Django Channel - Nginx cannot connect to websocket

I've been stuck for days just to find a way to fix this problem.
Why my Nginx can't connect to WebSocket? and always get these errors on the console:
WebSocket connection to '<URL>' failed: WebSocket is closed before the connection is established.
or
WebSocket connection to 'wss://domain.com/virtualexpo/' failed: Error during WebSocket handshake: Unexpected response code: 404
Here's my Nginx setup looks like:
upstream projectname {
server localhost:9001;
}
upstream uvsock {
server 127.0.0.1:6379;
# server unix://var/run/supervisor.sock;
}
server {
server_name domain.com www.domain.com;
sendfile on;
charset utf-8;
client_max_body_size 20M;
client_body_buffer_size 80M;
client_body_timeout 50;
location /ws/ {
proxy_pass http://uvsock;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
location / {
proxy_pass http://projectname;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
...
}
location /static {
alias /home/username/server/vier/staticfiles;
}
location /media {
alias /home/username/server/vier/media;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.domain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = domain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name domain.com www.domain.com;
return 404; # managed by Certbot
}
How can I connect this Nginx with my WebSocket for use with Django Channel?
Here's my routing.py looks like:
application = ProtocolTypeRouter({
# "http": get_asgi_application(),
'websocket': AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
[
path('stream/<pk>/', LiveStreamConsumer),
path('discussion/global/', GlobalLiveChatConsumer),
path('somepath/', VirtualExpoConsumer)
]
)
)
)
})
The ASGI setup:
...
from django.core.asgi import get_asgi_application
from channels.layers import get_channel_layer
from channels.routing import get_default_application
os.environ['DJANGO_SETTINGS_MODULE'] = 'core.settings'
django.setup()
channel_layer = get_channel_layer()
application = get_default_application()
# application = get_asgi_application()
And my settings.py looks like this:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
},
},
}
Been around looking for a way to fix them but can't find any.
The celery and Redis themselves have already run with no issue.
But it seems that the WebSocket can't connect with my Nginx config.
This is might due to your daphne server wasn't able to access the cert to redirect to wss. You may refer article here.

Static files do not work in django-admin after adding Https - Django

After adding the SSL certificate, my static files do not work only in django-admin. Other files on the entire website work very well.
How can I fix this situation (preferably without brutal copying of django-admin static files to my application)?
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('app.urls', namespace='app')),
path('media/<path>/', serve,{'document_root': settings.MEDIA_ROOT}),
path('static/<path>/', serve,{'document_root': settings.STATIC_ROOT}),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '../static/')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'app/media')
app (/etc/nginx/sites-available/app) After making changes to this file, they django-admin static file stopped working.
upstream app_server {
server unix:/home/app/run/gunicorn.sock fail_timeout=0;
}
server {
#listen 80;
# add here the ip address of your server
# or a domain pointing to that ip (like example.com or www.example.com)
listen 443 ssl;
server_name ebluedesign.online;
ssl_certificate /etc/letsencrypt/live/ebluedesign.online/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ebluedesign.online/privkey.pem;
server_name 101.170.18.112;
keepalive_timeout 5;
client_max_body_size 4G;
access_log /home/app/logs/nginx-access.log;
error_log /home/app/logs/nginx-error.log;
location /static/ {
alias /home/app/app/app/static/;
}
# checks for static file, if not found proxy to app
location / {
try_files $uri #proxy_to_app;
}
location #proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
server {
listen 80;
server_name ebluedesign.online;
return 301 https://$host$request_uri;
}

Host Django on subfolder

I have deployed Django with Gunicorn and NGINX, and it works fine, if the Django app is served on the root url, with this configuration:
server {
listen 80;
location = /favicon.ico { access_log off; log_not_found off; }
location / {
include proxy_params;
proxy_pass http://unix:my_app.sock;
}
}
However when I try to serve the Django app on another URL, it doesn't work.
If I try to access http://domain/my_app/admin/ then Django tells me it cannot find the view.
This is the NGINX config:
server {
listen 80;
location = /favicon.ico { access_log off; log_not_found off; }
location /my_app {
include proxy_params;
proxy_pass http://unix:/var/my_app/app.sock;
}
}
How could I make this work? I was not able to find any solution to specify something like a "BASE_URL" so far.
My comment doesn't show the whole picture. When I've run Django sites on subfolders, I like to use a dynamic config so that you can still access the machine directly (without the proxy) and have a working web-app. This can help a LOT for debugging tricky stuff like this that is hard to reproduce in dev.
If you do not have the ability to pass the header or modify wsgi.py, you can still set FORCE_SCRIPT_NAME in your Django settings.
3 steps:
set up a proxy in front of the webserver that strips the subfolder out of the URL
set the X-Script-Name header so that your Django site generates its urls with /myapp/ infront of them -- make sure you're using the {% url %} tag and reverse, vs. hard-coding!
modify myapp/wsgi.py to read a new header X-Script-Name into the wsgi environment variable SCRIPT_NAME (based on this flask snippet)
Here is an example Nginx config for a proxy that points to a Django site on a subdirectory and also sets X-Script-Name (steps 1 and 2), note that this doesn't use a unix socket, so it's a little different from the OP's question. Would welcome an edit:
nginx.conf
location /my_app {
proxy_pass https://mywebapp.com/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Script-Name /my_app;
proxy_cookie_path / /my_app;
}
And to read X-Script-Name:
myapp/wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
_application = get_wsgi_application()
def application(environ, start_response):
# http://flask.pocoo.org/snippets/35/
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '')
if scheme:
environ['wsgi.url_scheme'] = scheme
return _application(environ, start_response)
#andyC thank you for your answer.
With up-to-date Django (4.1.4) it worked with the following settings. I made the following setting in nginx for django, which is behind the api gateway.
settings.py
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = '/content/'
SESSION_COOKIE_PATH = '/content/'
LOGIN_URL = "login/"
LOGIN_REDIRECT_URL = '/content/'
LOGOUT_REDIRECT_URL = '/content/'
STATIC_URL = '/content/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
# Media files
MEDIA_URL = '/content/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles/")
apiGateway -> nginx.conf
server_name api.mydomain.com;
location /auth/ {
proxy_pass http://django_app:8002/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
if you run django with gunicorn and use uvicorn as asgi worker, like
gunicorn example:asgi.app -w 4 -k uvicorn.workers.UvicornWorker
you need to add root_path='/api/' to django asgi scope, unfortunately, gunicorn can't pass this thought arguments but you can write a custom worker and run gunicorn with it
class MyUvicornWorker(UvicornWorker):
CONFIG_KWARGS = {"loop": "auto", "http": "auto", "root_path": "/api/"}
and then run gunicorn with custom worker
gunicorn example:asgi.app -w 4 -k example.workers.MyUvicornWorker
Here is what I solve this problem. I can run multiple django running on same server/domain with subdirectory.
project/settings.py
MY_PROJECT = env('MY_PROJECT', '') # example; '/dj'
if MY_PROJECT:
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = MY_PROJECT + "/"
SESSION_COOKIE_PATH = MY_PROJECT + "/"
LOGIN_URL = "login/"
LOGIN_REDIRECT_URL = MY_PROJECT + "/"
LOGOUT_REDIRECT_URL = MY_PROJECT + "/"
NGINX configuration
location /dj/ {
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8000/;
}
Be aware that location url should end with "/"

django output wrong media url

Django version is 1.10.3
Static file server is nginx
Debug mode off
The output media url has an absolute path in the server.
eg: http://127.0.0.1:8001/home/ken/hc/media/uploads/q/2017/03/01/hjqtye.png
The correct url is: http://127.0.0.1:8001/media/uploads/q/2017/03/01/hjqtye.png
How can i fix it? THX.
The relevant code as below.
settings.py
INSTALLED_APPS = [
'grappelli',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ckeditor',
'ckeditor_uploader',
'imagekit',
'debug_toolbar',
'gunicorn',
'Website',
]
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
STATICFILES_DIRS = [(os.path.join(BASE_DIR, 'collected_static'))]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
CKEDITOR_UPLOAD_PATH = "uploads/"
#CKEDITOR_UPLOAD_PATH = os.path.join(BASE_DIR, MEDIA_ROOT, 'uploads')
Nginx conf file
server {
listen 8001;
server_name 127.0.0.1;
access_log /var/log/nginx/hc.access.log;
error_log /var/log/nginx/hc.error.log;
location / {
#uwsgi_pass 127.0.0.1:8010;
#include uwsgi_params;
proxy_pass http://127.0.0.1:8010;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /media/ {
alias /home/ken/hc/media/;
expires 1h;
access_log off;
#add Cache-Control 'public';
}
location /static/ {
alias /home/ken/hc/collected_static/;
expires 1h;
access_log off;
#include /etc/nginx/mime.types;
#add Cache-Control 'public';
}
}