django-private-storage configuration in nginx and Docker - django

I am trying to use django-private-storage package to protect a model's file from being accessed
or downloaded by users who are not owners of the file.
I was able to do it successfully in development (using python manage.py runserver)
In development, I am using nginx configured via docker.
I can create objects with both FileField and PrivateFileField. My problem is accessing the urls associated with a PrivateFileField.
The mediafiles are being served as expected (e.g. when I access the url of a FileField), but I get a "404 Not Found" error from nginx when I access the url of a PrivateFileField.
My hunch is that the server response is not properly configured to have a 'X-Accel-Redirect' data,
thus treating the response not internal.
If I remove the line "internal;" in my nginx.conf for the private-data location, the PrivateFile is served
properly, although, now, it is not private.
location /private-data/ {
internal; #<------ the PrivateFile can be accessed if this line is removed
alias /home/app/web/private-data/;
}
Also, I am sure that the private file was saved in /home/app/web/private-data
Am I missing out something in the implementation?
Thanks in advance.
Additional info:
nginx version: 1.17.4
django-private-storage version: 2.2.2
My production setup follows this:
https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/
FILES -----------------------------------
docker-compose.prod.yml
version: '3.7'
services:
web:
build:
context: ./web_app
dockerfile: Dockerfile.prod
command: gunicorn notify_django_project.wsgi:application --bind 0.0.0.0:8000
volumes:
- static_volume:/home/app/web/staticfiles
- media_volume:/home/app/web/mediafiles
- private_volume:/home/app/web/private-data
expose:
- 8000
env_file:
- ./.env.prod
depends_on:
- db
db:
image: postgres:12.0-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- ./.env.prod.db
nginx:
build: ./nginx
volumes:
- static_volume:/home/app/web/staticfiles
- media_volume:/home/app/web/mediafiles
- private_volume:/home/app/web/private-data
ports:
- 1337:80
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:
private_volume:
nginx.conf
upstream django_project {
server web:8000;
}
server {
listen 80;
location / {
proxy_pass http://django_project;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /staticfiles/ {
alias /home/app/web/staticfiles/;
}
location /mediafiles/ {
alias /home/app/web/mediafiles/;
}
location /private-data/ {
internal;
alias /home/app/web/private-data/;
}
}
settings.py
INSTALLED_APPS = [
...
'private_storage',
....
]
PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, "private-data")
PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_authenticated'
PRIVATE_STORAGE_INTERNAL_URL = '/private-data/'
PRIVATE_STORAGE_SERVER = 'nginx'
models.py
class Message(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
subject = models.CharField(max_length=255)
attachment = models.FileField(upload_to=get_attachment_save_path, null=True, blank=True)
private_attachment = PrivateFileField(upload_subfolder=get_private_attachment_save_path, null=True, blank=True)
urls.py
urlpatterns = [
...
path('private-data/<str:code>/<int:year>/<str:subdir>/<uuid:pk>/<str:filename>', DownloadPrivateFileView.as_view(), name="file_download"),
url('^private-data/', include(private_storage.urls)),
...
]
views.py
#method_decorator(login_required, name='dispatch')
class DownloadPrivateFileView(PrivateStorageDetailView):
model = Message
model_file_field = 'private_attachment'
def can_access_file(self, private_file):
# When the object can be accessed, the file may be downloaded.
# This overrides PRIVATE_STORAGE_AUTH_FUNCTION
# grant_access checks private_file ownership
grant_access = grant_note_access(private_file.request, message=self.get_object())
return grant_access

Iam in the testing phase with this library too!
I did not use these lines that indicated, which serves to speed up uploading large files.
without these settings and debug = False, everything worked correctly.
Take the test please.
Sorry for the Translation, I don't speak English

My conf for my site in nginx mysite.conf
server {
listen 80;
server_name mysite.com.br;
return 301 https://mysite.com.br$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mysite.com.br;
location ~ ^/.well-known{
root /var/www/myapp;
}
location / {
proxy_pass http://127.0.0.1:6010; # My container is at port 3020
}
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# Certificate free letsencrypt
ssl_certificate /etc/letsencrypt/live/mysite.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mysite.com.br/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
}
My setting.py for django:
MEDIA_ROOT = os.path.join(BASE_DIR, 'anexosapp') # Folder for files private app
MEDIA_URL = '/docs/'
# Conf for django-private-storage
INSTALLED_APPS += (
'private_storage',
)
PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, 'anexosapp/')
PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_authenticated' # allow user authenticated
# settings for static server over whitenoise
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"), ]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
urls.py app main:
urlpatterns += [
path('private-media/', include(private_storage.urls)),
]
The file access url looks like this
https : //mysite.com.br/private-media/docs/namefile.pdf
If anyone finds errors, tips for improving the settings, please indicate! Thank you

I just removed from nginx.conf location that refers to private media like so:
upstream "my domain" {
server web:8000;
}
server {
listen 80;
location / {
proxy_pass http://"my domain";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /staticfiles/ {
alias /home/app/web/staticfiles/;
}
location /mediafiles/ {
alias /home/app/web/mediafiles/;
}
#location /privatefiles/ {
# alias /home/app/web/privatefiles/;
#}
# Error & Access logs
error_log /home/app/logs/error.log error;
access_log /home/app/logs/access.log;
client_max_body_size 128m;
}
Don't forget to set DEBUG = False, then it should worked perfectly. Every time I tried to access to private media without login in, it redirected me to login page.
This is my settings.py
...
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
STATIC_URL = "/staticfiles/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
MEDIA_URL = "/mediafiles/"
MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles")
PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, "privatefiles")
PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_authenticated'
...
and my main urls.py
from django.conf.urls.static import static
from django.conf.urls import url
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
import private_storage.urls <--- this is for private storage
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('core.urls')),
path('rubric/', include('rubric.urls')),
path('warehouse/', include('warehouse.urls')),
path('preoffers/', include('preoffers.urls')),
path('offers/', include('offers.urls')),
url('^privatefiles/', include(private_storage.urls)) <--- this is for private storage
]
if settings.DEBUG:
urlpatterns += static(
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(
settings.STATIC_URL, document_root=settings.STATIC_ROOT)

'internal' param tells nginx it's not accessible from the outside.
We access application and then redirect to nginx
settings.py
PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, 'private-media')
PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_staff'
PRIVATE_STORAGE_SERVER = 'nginx'
PRIVATE_STORAGE_INTERNAL_URL = '/private-x-accel-redirect/'
nginx
location /private-x-accel-redirect/ {
internal;
alias /var/www/private-media/;
}

Related

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;
}

Django Wagtail return HTTP 500 Internal server error

I'm deploying my Wagtail application to production but could not get it to work. I'm following this tutorial https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-18-04.
The website is work as expected on my server when using development settings, as soon as I changed to production it won't work.
On production, I'm only able to access the admin and sitemap URL.
production.py
from .base import *
with open('/etc/secret_key.txt') as f:
SECRET_KEY = f.read().strip()
DEBUG = False
try:
from .local import *
except ImportError:
pass
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'name',
'USER': 'user',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '',
}
}
# SECURITY WARNING: define the correct hosts in production!
INTERNAL_IPS = ("127.0.0.1")
ALLOWED_HOSTS = ['*']
nginx
# Redirect unencrypted traffic to the encrypted site
server {
listen 80;
server_name domain www.domain IP;
return 301 https://domain$request_uri;
}
server {
client_max_body_size 20M;
listen 443 default ssl;
server_name domain.com IP;
keepalive_timeout 70;
ssl on;
ssl_certificate /etc/nginx/certs.pem;
ssl_certificate_key /etc/nginx/privkey.pem;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/user/projectdir;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
Gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=sherpa
Group=www-data
WorkingDirectory=/home/user/projectdir
ExecStart=/home/user/projectenv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
project.wsgi_production:application
[Install]
WantedBy=multi-user.target
urls.py
urlpatterns = [
url(r'^django-admin/', admin.site.urls),
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
url(r'^search/$', search_views.search, name='search'),
url(r'^sitemap.xml', sitemap),
# For anything not caught by a more specific rule above, hand over to
# Wagtail's page serving mechanism. This should be the last pattern in
# the list:
url(r'', include(wagtail_urls)),
# Alternatively, if you want Wagtail pages to be served from a subpath
# of your site, rather than the site root:
# url(r'^pages/', include(wagtail_urls)),
]
I'm having the same issue. If I set to Debug = True, everything works fine. If I set Debug = False I get the 500 error page, but nothing in the logs to tell me an error has been fired. I am using Apache and not nginx.

Ubuntu server, Django 1.11.4, gunicorn, nginx can not find css files

Got problem with static css. I already did collectstatic.
Css works fine if run
./manage.py runserver 0.0.0.0:8000
but can not be found if run
gunicorn --bind 0.0.0.0:8000 hotel_main.wsgi:application
same situation with Dajango admin
settings.py
STATIC_URL = '/static/'
STATIC_ROOT = "/opt/static/"
STATICFILES_DIRS = [
('static', os.path.join(BASE_DIR, 'hotel_site/static'),),
('static', os.path.join(BASE_DIR, 'static'),),
]
Urls.py
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.conf import settings
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
url(r'^', include('hotel_site.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Nginx file
upstream 78.155.199.17 {
server localhost:8000 fail_timeout=0;
}
server {
listen 80;
server_name 78.155.199.17;
return 301 78.155.199.17$request_uri;
}
server {
listen 80;
server_name 78.155.199.17;
location /static/ {
root /opt/;
}
location /media/ {
root /root/;
}
location / {
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_pass 78.155.199.17;
}
}
Project tree
opt/
└─ static/
├─admin/
├─ckeditor/
└─static/
└─foundation/
root/
└─ ramn_hotel/
Recently did as here. It worked as it should.

Digital Ocean One-Click-Install-Image Django/Ngnix with HTTPS

I'm fairly new to django and nginx, and I started using DigitalOcean's one-click-image install Django 1.6 environment which uses nginx and gunicorn. The default specifications and details can be found here https://www.digitalocean.com/community/tutorials/how-to-use-the-django-one-click-install-image.
Recently, I have been trying to figure out how to secure the admin page for deployment with SSL/HTTPS to prevent login capture. And I realize there is information on this on stackoverflow already. However, it seems like most information has base settings for nginx that differ from Digital Oceans. So, I'm a little thrown for what I should keep, edit and delete. At this moment I'm satisfied with proxy over two instances in nginx: flat pages being under HTTP and the admin under HTTPS as this is simply going to be a launch page. How would you secure the entire site behind https? What would be the necessary modifications to the following nginx and Django settings?
Nginx Settings
upstream app_server {
server 127.0.0.1:9000 fail_timeout=0;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
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/media;
}
# your Django project's static files - amend as required
location /static {
alias /home/django/django_project/static;
}
location / {
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;
}
}
Django Settings
"""Production settings and globals."""
from __future__ import absolute_import
from os import environ
from .base import *
SESSION_COOKIE_SECURE = True
CRSF_COOKIE_SECURE = True
# Honor the 'X-Fowarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
########## HOST CONFIGURATION
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/#allowed-hosts-required-in- production
ALLOWED_HOSTS = [
'localhost',
'{{website url}}',
]
########## END HOST CONFIGURATION
########## EMAIL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host
EMAIL_HOST = environ.get('EMAIL_HOST', 'smtp.gmail.com')
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host-password
EMAIL_HOST_PASSWORD = environ.get('EMAIL_HOST_PASSWORD', '')
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host-user
EMAIL_HOST_USER = environ.get('EMAIL_HOST_USER', 'your_email#example.com')
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-port
EMAIL_PORT = environ.get('EMAIL_PORT', 587)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
EMAIL_SUBJECT_PREFIX = '[%s] ' % SITE_NAME
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-use-tls
EMAIL_USE_TLS = True
# See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = EMAIL_HOST_USER
########## END EMAIL CONFIGURATION
########## DATABASE CONFIGURATION
DATABASES = {}
########## END DATABASE CONFIGURATION
########## CACHE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
CACHES = {}
########## END CACHE CONFIGURATION
########## SECRET CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
SECRET_KEY = get_secret("SECRET_KEY")
########## END SECRET CONFIGURATION

Static files in Nginx, Gunicorn in Django

i have try every configuration that i found and the static files don't get loaded, so i doesn't know what's wrong. I create the app using Pycharm.
Can someone give me a hand to fix this?
Here are the configurations.
settings.py
MEDIA_ROOT = ''
MEDIA_URL = '/Users/gcarranza/PycharmProjects/clouddemyTest/'
STATIC_ROOT = ''
STATIC_URL = '/Users/gcarranza/PycharmProjects/clouddemyTest/static/'
STATICFILES_DIRS = (
'/Users/gcarranza/PycharmProjects/clouddemyTest/static',)
nginx conf:
server {
listen 80;
server_name localhost;
location /static/ {
autoindex on;
alias /Users/gcarranza/PycharmProjects/clouddemyTest/static/;
}
location / {
proxy_pass http://127.0.0.1:8000;
}
}
Gunicorn:
gunicorn_django -b localhost:8000
You got the root and url backwards. Should be:
STATIC_ROOT = '/Users/gcarranza/PycharmProjects/clouddemyTest/static/'
STATIC_URL = '/static/'
And same for media