'Django collectstatic Permission denied with docker-compose

I'm making a Django app and I'm using Docker por production deployment, the application almost runs fine on the VPS(Ubuntu 20.04) except that when I try to run collectstatic with this command:

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

Always throws this error:

PermissionError: [Errno 13] Permission denied: '/home/app/web/staticfiles/img/app_logo.png'

This is my docker-compose:

version: '3'
services:
  db:
    restart: unless-stopped
    image: "postgres:13.2-alpine"
    container_name: db
    ports:
      - "5432:5432" # HOST:CONTAINER
    env_file:
      - ./.env.prod
    volumes:
      - ./pgdata:/var/lib/postgresql/data
  web:
    container_name: web
    restart: unless-stopped
    build:
      context: .
      dockerfile: ./docker/production/Dockerfile
    environment:
      DJANGO_SETTINGS_MODULE: MyApp.app_settings.production
    command: gunicorn MyApp.wsgi:application --bind 0.0.0.0:8000
    expose:
      - "8000"
    env_file:
      - ./.env.prod
    volumes:
      - .:/app # Enable code reload
      - ./run/static:/home/app/web/staticfiles
      - ./run/media:/home/app/web/mediafiles
    depends_on:
      - db
  nginx:
    container_name: nginx
    restart: unless-stopped
    build: docker/production/nginx
    volumes:
      - ./run/static:/home/app/web/staticfiles
      - ./run/media:/home/app/web/mediafiles
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - web

and this is my Dockerfile:

# pull official base image
FROM python:3.8

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

# create the app user
#RUN addgroup -S app && adduser -S app -G app
RUN adduser --system --group 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

# Own home directory
RUN chown -R app:app $HOME

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install dependencies
#RUN apk update && apk add libpq
#COPY --from=builder /usr/src/app/wheels /wheels
#COPY --from=builder /usr/src/app/requirements.txt .
#RUN pip install --no-cache /wheels/*

COPY ./requirements.txt $APP_HOME
RUN pip install --no-cache-dir -r requirements.txt

RUN apt-get clean
RUN apt-get update
# Install netcat
RUN apt install -y netcat
# Install wkhtml2pdf
RUN wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb
RUN DEBIAN_FRONTEND=noninteractive apt install -y -q ./wkhtmltox_0.12.6-1.buster_amd64.deb

# copy entrypoint-prod.sh
COPY ./docker/prod/ep.prod.sh $APP_HOME

# execution permissions
RUN ["chmod", "+x", "/home/app/web/ep.prod.sh"]

# copy project
#COPY . $APP_HOME
COPY --chown=app:app . $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/ep.prod.sh"]

I believe that my Dockerfile should have something wrong, but I don't know exactly what. Anyone can help me?

Edit: With the answer below, they suggest to run it this way and works fine:

docker exec -it -u 0 [CONTAINER_NAME] python manage.py collectstatic --no-input

Also I found this solution, but I believe that this is not safe, any other suggestion?

chmod a+rwx -R run/

I followed this tutorial: https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/



Solution 1:[1]

You must add -u 0 to your command for run as root user:

docker exec -it -u 0 [CONTAINER_NAME] python manage.py collectstatic --no-input

Solution 2:[2]

I have been stuck for a few hours on this issue. After making sure all the static directory and Django config are in place and proper privileges via shell onto the container. I was with no success.

After searching for a few hours, came to this document which says you need to manually collect static after demonizing the container.

Commands:

docker-compose up -d --build
docker-compose exec <your-web-service> python manage.py collectstatic --no-input --clear

The answer may long be solved but reference to future users, who would be in the same issue.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 alirezadp10
Solution 2 Vimm Rana