Add option to serve media files locally using nginx (#2457)

* Add option to serve media files locally using nginx

* Fix nginx media location and storage issue

* Fix traefik django-media typo

* Add certresolver property to web-media-router

* Add trailing slash in nginx configuration to avoid path traversal exploits

* Remove autoindexing from nginx configuration so nginx uses its default off setting

* Use nginx to serve media files if cloud provider is None

* Add back warning about lack of media files without Docker or Cloud providers

* Update documentation

* Fix typos and rephrase

Co-authored-by: Arkadiusz Ryś <arkadiusz.michal.rys@gmail.com>

---------

Co-authored-by: Bruno Alla <alla.brunoo@gmail.com>
Co-authored-by: Bruno Alla <browniebroke@users.noreply.github.com>
This commit is contained in:
Arkadiusz Michał Ryś 2023-03-04 19:36:11 +01:00 committed by GitHub
parent 46868bed26
commit 06369bfd4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 57 additions and 4 deletions

View File

@ -31,7 +31,7 @@ production-ready Django projects quickly.
- Optional basic ASGI setup for Websockets
- Optional custom static build using Gulp or Webpack
- Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable)
- Media storage using Amazon S3, Google Cloud Storage or Azure Storage
- Media storage using Amazon S3, Google Cloud Storage, Azure Storage or nginx
- Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support)
- [Procfile](https://devcenter.heroku.com/articles/procfile) for deploying to Heroku
- Instructions for deploying to [PythonAnywhere](https://www.pythonanywhere.com/)

View File

@ -187,3 +187,7 @@ For status check, run::
supervisorctl status
Media files without cloud provider
----------------------------------
If you chose no cloud provider and Docker, the media files will be served by an nginx service, from a ``production_django_media`` volume. Make sure to keep this around to avoid losing any media files.

View File

@ -69,7 +69,7 @@ cloud_provider:
3. Azure_
4. None
Note that if you choose no cloud provider, media files won't work.
If you choose no cloud provider and docker, the production stack will serve the media files via an nginx Docker service. Without Docker, the media files won't work.
mail_service:
Select an email service that Django-Anymail provides

View File

@ -491,9 +491,12 @@ def main():
use_async=("{{ cookiecutter.use_async }}".lower() == "y"),
)
if "{{ cookiecutter.cloud_provider }}" == "None":
if (
"{{ cookiecutter.cloud_provider }}" == "None"
and "{{ cookiecutter.use_docker }}".lower() == "n"
):
print(
WARNING + "You chose not to use a cloud provider, "
WARNING + "You chose to not use any cloud providers nor Docker, "
"media files won't be served in production." + TERMINATOR
)
remove_storages_module()

View File

@ -0,0 +1,2 @@
FROM nginx:1.17.8-alpine
COPY ./compose/production/nginx/default.conf /etc/nginx/conf.d/default.conf

View File

@ -0,0 +1,7 @@
server {
listen 80;
server_name localhost;
location /media/ {
alias /usr/share/nginx/media/;
}
}

View File

@ -57,6 +57,18 @@ http:
# https://docs.traefik.io/master/routing/routers/#certresolver
certResolver: letsencrypt
{%- endif %}
{%- if cookiecutter.cloud_provider == 'None' %}
web-media-router:
rule: "Host(`{{ cookiecutter.domain_name }}`) && PathPrefix(`/media/`)"
entryPoints:
- web-secure
middlewares:
- csrf
service: django-media
tls:
certResolver: letsencrypt
{%- endif %}
middlewares:
csrf:
@ -77,6 +89,13 @@ http:
servers:
- url: http://flower:5555
{%- endif %}
{%- if cookiecutter.cloud_provider == 'None' %}
django-media:
loadBalancer:
servers:
- url: http://nginx:80
{%- endif %}
providers:
# https://docs.traefik.io/master/providers/file/

View File

@ -4,6 +4,9 @@ volumes:
production_postgres_data: {}
production_postgres_data_backups: {}
production_traefik: {}
{%- if cookiecutter.cloud_provider == 'None' %}
production_django_media: {}
{%- endif %}
services:
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
@ -24,6 +27,10 @@ services:
{%- endif %}
image: {{ cookiecutter.project_slug }}_production_django
{%- if cookiecutter.cloud_provider == 'None' %}
volumes:
- production_django_media:/app/{{ cookiecutter.project_slug }}/media
{%- endif %}
depends_on:
- postgres
- redis
@ -89,3 +96,14 @@ services:
volumes:
- production_postgres_data_backups:/backups:z
{%- endif %}
{%- if cookiecutter.cloud_provider == 'None' %}
nginx:
build:
context: .
dockerfile: ./compose/production/nginx/Dockerfile
image: {{ cookiecutter.project_slug }}_local_nginx
depends_on:
- django
volumes:
- production_django_media:/usr/share/nginx/media:ro
{%- endif %}