0

I need to launch my site in production, so I decided to do it with Docker container(at first time, newbie there) with Postgres, nginx and Django, everything is working inside a container, but on launched site I have in console 404 error with static and media. I did a research, but still haven't found the answer for my case. Could somebody advise what I need to fix there?

There is my Dockerfile

###########
# BUILDER #
###########

# pull official base image
FROM python:3.9.6-alpine as builder

# set work directory
WORKDIR /usr/src/my_shop

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install psycopg2 and Pillow dependencies
RUN apk update \
    && apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev
    # && pip install Pillow

# lint
RUN pip install --upgrade pip
RUN apk add build-base python3-dev py-pip jpeg-dev zlib-dev
ENV LIBRARY_PATH=/lib:/usr/lib

# install dependencies
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/my_shop/wheels -r requirements.txt

#########
# FINAL #
#########

# pull official base image
FROM python:3.9.6-alpine

# create directory for the app user
RUN mkdir -p /home/app

# create the app user
RUN addgroup -S app && adduser -S app -G app

# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/staticfiles
RUN mkdir $APP_HOME/mediafiles
WORKDIR $APP_HOME

# install dependencies
RUN apk update && apk add libpq gcc python3-dev musl-dev jpeg-dev zlib-dev \
    && pip install --no-cache-dir Pillow
COPY --from=builder /usr/src/my_shop/wheels /wheels
COPY --from=builder /usr/src/my_shop/requirements.txt .
RUN pip install --no-cache /wheels/*

# copy entrypoint.prod.sh
COPY ./entrypoint.prod.sh .
RUN sed -i 's/\r$//g'  $APP_HOME/entrypoint.prod.sh
RUN chmod +x  $APP_HOME/entrypoint.prod.sh

# copy project
COPY . $APP_HOME

# chown all the files to the app user
RUN chown -R app:app $APP_HOME

# change to the app user
USER app

# run entrypoint.prod.sh
ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"]

There is docker-compose.yml

version: '3.8'

services:
  web:
    build:
      context: ./
      dockerfile: Dockerfile.prod
    command: gunicorn shop.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - static_volume:/home/app/web/staticfiles
      - media_volume:/home/app/web/mediafiles
    ports:
      - 8000:8000
    env_file:
      - ./.env.prod
    depends_on:
      - db
  db:
    image: postgres:13.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
    ports:
      - "80:80"
    depends_on:
      - web

volumes:
  postgres_data:
  static_volume:
  media_volume:

and there is nginx settings:

upstream shop {
    server web:8000;
}

server {

    listen 80;

    location / {
        proxy_pass http://shop;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

    location /static/ {
        alias /home/app/web/staticfiles/;
    }

    location /media/ {
        alias /home/app/web/mediafiles/;
    }
}

What I have in settings.py

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_FINDERS = [
    "django.contrib.staticfiles.finders.FileSystemFinder",
    "django.contrib.staticfiles.finders.AppDirectoriesFinder",
]

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / "mediafiles"

Dockerfile for nginx

FROM nginx:1.21-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d

And of course after container launching I did:

docker-compose -f docker-compose.prod.yml exec web python manage.py migrate --noinput

and then

docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic --no-input --clear

I did it according to this instruction with some fixes https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/

  • The Dockerfile for the Nginx container would be good to see. Can you add it to your post, please? – Hans Kilian Feb 03 '22 at 06:30
  • Where are the static and media files in host machine? – Aleksey Vaganov Feb 03 '22 at 06:30
  • I added additional information. After command "collectstatic" they should appear in "staticfiles" as it set in django settings.py: STATIC_ROOT = BASE_DIR / "staticfiles" and for media "MEDIA_ROOT = BASE_DIR / "mediafiles"" if I understood you right Alexey ). At this stage I'm testing via admin site after container launching: "127.0.0.1:8000/admin/" and get 404 error with static. – Алексей sk1p Feb 03 '22 at 07:23
  • You map the two directories to two docker volumes. How do the files get into the volumes? Maybe your problem is that the volumes are empty? – Hans Kilian Feb 03 '22 at 08:00
  • I suppose the problem connected with folders, I need to understand what is happening inside the container, I will try to install DockStation to check the created folders. – Алексей sk1p Feb 03 '22 at 08:32
  • 1
    Find the name of the nginx container using `docker ps`. Then do `docker exec ls /home/app/web/staticfiles`. You should see the file names listed if they're there. – Hans Kilian Feb 03 '22 at 09:43
  • thank you, I will try – Алексей sk1p Feb 03 '22 at 10:34
  • It looks like your Django application is set up to serve static files already. Does it work to remove the `/static` and `/media` routes from the Nginx configuration and to remove the `volumes:` blocks from the Compose configuration for the `web` and `nginx` containers? That would cause the Django application to serve static files out of its own image, without involving the complexities of Docker volumes at all. – David Maze Feb 03 '22 at 11:35
  • I saw that solution somewhere with /static(to not use "/static/"), but it doesn't help. Thank you, as a variant I will try to remove theses volumes – Алексей sk1p Feb 03 '22 at 13:21
  • I have: C:\Users\79091\Desktop\my_shop>docker exec my_shop-nginx-1 ls ``` /home/app/web/staticfiles admin rest_framework store ``` So I have these folders, but nginx doesn't work with static or media Also I see this error in Docker: 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist May this is a problem? – Алексей sk1p Feb 08 '22 at 16:24
  • I found my mistake :D All this time I opened my site with 8000:8000 port, but I should expose this port and use only 80 ! ) These settings are working, just my mistake that I had two ports outside: 8000 and 80 xD and used 8000 as usual, but I need to use NGINX port 80 ! and enter the site via http://127.0.0.1:80 !!)) – Алексей sk1p Feb 09 '22 at 10:25

0 Answers0