@@ -10,7 +10,7 @@ WORKDIR /app
# Install dependencies
COPY requirements.txt /app/
-RUN pip install -r requirements.txt
+RUN pip install -r requirements.txt gunicorn==26.2.0
# Copy the project code into the container
COPY . /app/
@@ -1,4 +1,3 @@
-version: '3'
services:
db:
image: mysql:8.4
@@ -23,14 +22,27 @@ services:
context: .
dockerfile: Dockerfile
container_name: error_report_web_backend
- command: sh -c "python3 manage.py migrate --noinput && python3 manage.py runserver 0.0.0.0:8000"
+ command: sh -c "python3 manage.py migrate --noinput && python3 manage.py collectstatic --noinput && gunicorn project.wsgi --bind=:8000 --workers=4 --timeout=60"
restart: always
- ports:
- - "8000:8000"
+ volumes:
+ - static:/app/staticfiles
env_file:
- .env
depends_on:
db:
condition: service_healthy
+
+ web:
+ image: nginx:1.30
+ container_name: error_report_web_nginx
+ restart: always
+ ports:
+ - "8080:80"
+ volumes:
+ - ./docker/nginx.conf:/etc/nginx/nginx.conf:ro
+ - static:/usr/share/nginx/html/static:ro
+ depends_on:
+ - backend
volumes:
data:
+ static:
new file mode 100644
@@ -0,0 +1,49 @@
+# nginx in front of gunicorn, plain HTTP for local use. Production uses
+# nginx-ssl.conf.
+#
+# SPDX-License-Identifier: MIT
+
+error_log /dev/stdout info;
+worker_processes 1;
+pid /tmp/nginx.pid;
+
+events {
+ worker_connections 1024;
+ accept_mutex off;
+}
+
+http {
+ include mime.types;
+ default_type application/octet-stream;
+ access_log /dev/stdout combined;
+ sendfile on;
+
+ upstream app_server {
+ server backend:8000 fail_timeout=0;
+ }
+
+ server {
+ listen 80 default;
+ server_name _;
+ # Reports can be up to DATA_UPLOAD_MAX_MEMORY_SIZE (10MB).
+ client_max_body_size 10m;
+ keepalive_timeout 20;
+
+ # path for static files
+ root /usr/share/nginx/html;
+
+ location / {
+ try_files $uri @proxy_to_app;
+ }
+
+ location @proxy_to_app {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ # Overwrites the client's value; Django trusts it.
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Host $http_host;
+ proxy_redirect off;
+
+ proxy_pass http://app_server;
+ }
+ }
+}
@@ -105,7 +105,8 @@ MEDIA_URL = ''
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
-STATIC_ROOT = ''
+# Shared with nginx.
+STATIC_ROOT = '/app/staticfiles'
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
As in layerindex-web, nginx serves static files and proxies to gunicorn. Unlike it, nginx sets X-Forwarded-Proto and accepts 10MB reports. Drop the obsolete compose version key. AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling <tim.orling@konsulko.com> --- Dockerfile | 2 +- docker-compose.yaml | 20 ++++++++++++---- docker/nginx.conf | 49 ++++++++++++++++++++++++++++++++++++++ project/settings.py.docker | 3 ++- 4 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 docker/nginx.conf