diff --git a/Dockerfile b/Dockerfile index ccf7d28..5b4e6ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,7 @@ RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-r libpq-dev \ curl \ git \ + nginx \ # wand dependencies libmagickwand-6.q16-6 libmagickwand-6.q16hdri-6 \ && apt-get autoremove && rm -rf /var/lib/apt/lists/* @@ -33,6 +34,8 @@ ENV PATH=$VIRTUAL_ENV/bin:$PATH \ EXPOSE 8000 +RUN ln -fs /app/etc/nginx.conf /etc/nginx/sites-available/default + USER website RUN python -m venv $VIRTUAL_ENV diff --git a/Procfile b/Procfile index 9165cf7..0da497d 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,4 @@ -web: ./manage.py runserver 0.0.0.0:8000 +web: ./manage.py runserver 0.0.0.0:8080 watch-js: npm run build:js -- --watch watch-css: npm run build:css -- --watch watch-contrib: ./scripts/copy-npm-contrib.sh; while inotifywait -e modify ./scripts/copy-npm-contrib.sh; do ./scripts/copy-npm-contrib.sh; done diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 3064519..cd6a27b 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -17,6 +17,7 @@ services: - db ports: - 127.0.0.1:8000:8000 + - 127.0.0.1:8080:8080 redis: image: redis:6-alpine diff --git a/etc/gunicorn.conf.py b/etc/gunicorn.conf.py index e64a662..666dd82 100644 --- a/etc/gunicorn.conf.py +++ b/etc/gunicorn.conf.py @@ -4,7 +4,7 @@ wsgi_app = "website.wsgi:application" accesslog = "-" disable_redirect_access_to_syslog = True preload_app = True -bind = "0.0.0.0" +bind = "0.0.0.0:8080" max_requests = 1200 max_requests_jitter = 100 forwarded_allow_ips = "*" diff --git a/etc/nginx.conf b/etc/nginx.conf new file mode 100644 index 0000000..b74e740 --- /dev/null +++ b/etc/nginx.conf @@ -0,0 +1,50 @@ +server { + listen 8000; + + access_log /dev/stdout; + + gzip_static on; + + server_tokens off; + + set_real_ip_from 0.0.0.0/0; + real_ip_header X-Forwarded-For; + + location / { + proxy_buffers 32 4k; + proxy_connect_timeout 240; + proxy_headers_hash_bucket_size 128; + proxy_headers_hash_max_size 1024; + proxy_http_version 1.1; + proxy_read_timeout 240; + proxy_redirect http:// $scheme://; + proxy_send_timeout 240; + + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Method $request_method; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-Ssl on; + proxy_set_header X-Forwarded-Uri $request_uri; + proxy_set_header X-Original-Method $request_method; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Real-IP $remote_addr; + + proxy_pass http://localhost:8080; + } + + location /static { + expires 1y; + add_header Cache-Control "public, immutable"; + alias /app/collected-static; + } + + location /media { + expires 1h; + alias /app/media; + } +} diff --git a/website/urls.py b/website/urls.py index a76f33a..81a1a01 100644 --- a/website/urls.py +++ b/website/urls.py @@ -45,12 +45,6 @@ urlpatterns = [ path("", include("website.legacy.urls")), path("api/", include("website.api.urls", namespace="api")), path("", include(favicon_urls)), - # Some say it's a bad idea to serve media with Django - I don't care - re_path( - r"^%s(?P.*)$" % re.escape(settings.MEDIA_URL.lstrip("/")), - cache_control(max_age=60 * 60)(serve), - {"document_root": settings.MEDIA_ROOT}, - ), ] @@ -65,6 +59,15 @@ if settings.DEBUG: # Add django-debug-toolbar urlpatterns.append(path("__debug__/", include("debug_toolbar.urls"))) + urlpatterns.append( + # Media is served by nginx in production + re_path( + r"^%s(?P.*)$" % re.escape(settings.MEDIA_URL.lstrip("/")), + cache_control(max_age=60 * 60)(serve), + {"document_root": settings.MEDIA_ROOT}, + ) + ) + if settings.DEBUG or settings.TEST: urlpatterns.extend(