How can I access my static files from my Django app? - django

I have a Django app running in a Docker container. I am using Nginx to serve as the production server with a docker-compose file putting the app, Nginx and Postgres together in a network of containers. I set up my Dockerfile as follows:
FROM python:3.9.6-buster
ENV HOME=/home/app/
ENV APP_HOME=/home/app/web
RUN mkdir -p "${APP_HOME}/staticfiles"
# Create user
ENV PYTHONBUFFERED=1
WORKDIR $APP_HOME
COPY requirements.txt $APP_HOME
RUN pip install -r requirements.txt
COPY . $APP_HOME
which as you can see sets a staticfiles directory. However, following normal Django principals my file structure is /home/app/web/quote_checklist/static/quote_checklist when I exec into the web container.
I'm using the following in my settings.py
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
When I access the index page I am getting an error that the directory/file /home/app/web/staticfiles/quote_checklist/css/base.css is not found, suggesting my app is looking in this staticfiles directory, which has nothing in it. I tried removing the /staticfiles/ bit from my static volume as well but then the system just looks in /home/app/web/static/quote_checklist/css/base.css rather than following the normal Django path, which would be to look in quote_checklist/static/quote_checklist/css/base.css.
Does anyone have suggestions?

Related

nginx does not seeing static files, when launching with docker compose +gunicorn

The thing is that i have set up dockerfiles, docker-compose is running everything as it should be. Databases is connected and all the staff. But the only problem is, that i cant load staticfiles. Gunicorn informs, that files "Not Found" both admin, and rest_framework static files. Even though it creates 'static' in the root directory, but doesn't collect static there, while dockerfile run.
When im doing "docker-compose up" it says that `0 static files were copied to '/static', 165 unmodified
So far i have checked paths which are configured in STATIC_ROOT and STATIC URL.
Also, modified my docker-compose file:
version: '3.11'
services:
django_gunicorn:
volumes:
- static:/static/
env_file:
- .env
build:
context: .
ports:
- "8000:8000"
nginx:
build: ./nginx
volumes:
- ./backend/service/static:/backend/static
ports:
- "80:80"
depends_on:
- django_gunicorn
- db
db:
image: postgres
expose:
- 5432
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
volumes:
static:
Also i have inspected nginx config file one more time:
upstream django {
server django_gunicorn:8000;
}
server {
listen 80;
location / {
proxy_pass http://django;
}
location /static/ {
autoindex on;
alias /static/;
}
}
i have also tried different approaches to setting up root and url of staticfiles, but left it like this for now:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
Also there were suggestions to run "collectstatic" first, which i have already done, but no effect, so ive deleted static folder for now, because i didnt see 'static' folder in other applications as well.
entrypoint/sh
#!/bin/sh
python manage.py migrate --no-input
python manage.py collectstatic --no-input
gunicorn config.wsgi:application --bind 0.0.0.0:8000
Here is my Dockerfile:
FROM python:3.11
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt \
python manage.py collectstatic \
pip install python-dotenv
COPY ./backend /app
WORKDIR /app
COPY ./entrypoint.sh /
ENTRYPOINT ["sh", "/entrypoint.sh"]
Nginx must map STATIC_URL to STATIC_ROOT with respect to volume mapping in docker-compose.
docker-compose volume mapping for Nginx:
- static:/static/
virtual volume "static" to root directory /static/
Nginx location
location /static/ {
autoindex on;
alias /static/;
}
Maps STATIC_URL = /static/ to directory inside nginx container /static/ which matches docker-compose volume mapping we just mentioned. Location is supposed to match STATIC_URL because Django is generating those URLs and it does use STATIC_URL so static files URLs will begin with STATIC_URL and to catch those URLs nginx must use the same location. But alias value is not supposed to match STATIC_ROOT because we "deliver" static files to nginx via virtual volume mapping in docker-compose and they (static files) will appear for nginx just where we tell them to - - static:/static/ - nginx container will see them under /static/ path. Django settings do not affect this path.
Django project docker image
COPY ./backend /app
which means that BASE_DIR inside the container will be /app and this is exactly what collectstatic is reporting to you: '165 static files copied to '/app/static'
now we need to share those files with nginx via virtual volume by mapping virtual volume to the directory inside django project container with collected static files. Static files were collected to /app/static. Virtual volume shared with nginx is static, so
docker-compose volume mapping for Django project
- static:/app/static/

Getting localhost for next page url in production

hlo, I have deployed a Django rest app in production. When I call a list API there is a pagination, and I am getting localhost for next page URL.
I am using GenericViewSet and LimitOffsetPagination for pagination. My app is running in docker container.And it is pointed to a specific domain. We can access it using domain name "https://abc.xyz.com". But I have used python manage.py runserver:0.0.0.0:8000(it's just for testing) CMD for running the server.
Here is the image for more detail.
I am calling an live hosted API to get a list from postman. In response data list contains pagination, which contains "http://localhost:8000/api/transaction/?limit=10&offset=10&ordering=-pk&purpose=1". for next page link instead of domain name.
I have hosted application using docker. Following is my docker file:
# Set the working directory
WORKDIR /app
# Copy requirements file
COPY requirements.txt .
# Install dependencies
RUN pip install --upgrade pip && pip install -r requirements.txt
# Copy project files
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# Run migrations
RUN python manage.py makemigrations
RUN python manage.py migrate
# Expose the port 8000
EXPOSE 8000
# Start the server
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
What should I do to get "https://abc.xyz.com/api/transaction/" instead of "http://localhost:8000/api/transaction/"
You can use relative url in your html, something like this:
http://localhost:8000/nextpage/?page=2
to
<a href="/nextpage/?page=2" />
When you change to this, your url will be change to yourdomain/nextpage/?page2. So you can run your app in localhost or VM or in container without changing host or absolute url for one by one environment you set up in project.

Why does one of my static file is not found when deploying a Django app with Docker?

I am trying to do a django project and push it to Heroku. For now, I just try to make my container work locally. For my static files, I use Whitenoise. The problem I encounter is that my app work and all my statics work except one, script.js (the only file I have in the folder js). I have this error message on the docker console : Not Found: /static/js/script.js
This is my Dockerfile :
# pull official base image
FROM python:3.8-alpine
# set work directory
WORKDIR /pur_beurre
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV DEBUG 0
# install psycopg2
RUN apk update \
&& apk add --virtual build-essential gcc python3-dev musl-dev \
&& apk add postgresql-dev \
&& pip install psycopg2
# install dependencies
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# copy project
COPY . .
# collect static files
RUN python manage.py collectstatic --noinput
# add and run as non-root user
RUN adduser -D myuser
USER myuser
# run gunicorn
CMD gunicorn pur_beurre.wsgi:application --bind 0.0.0.0:$PORT
I have STATIC_URL = 'staticfiles' and STATIC_ROOT = BASE_DIR / 'staticfiles' and I added the line 'whitenoise.middleware.WhiteNoiseMiddleware', just after 'django.middleware.security.SecurityMiddleware',.
My js folder is at the same level as my css folder in /my_app/static/ and he is in /my_project/staticfiles/my_app/ like the css.
I found a way to see the docker static files deployed. sing the command docker exec django-heroku ls /my_project/staticfiles/my_app/js, I can see that script.js is in the folder.

React app not loading in AWS ECS Cluster?

I have the following dockerfile:
# Multi-stage
# 1) Node image for building frontend assets
# 2) nginx stage to serve frontend assets
# Name the node stage "builder"
FROM node:10 AS builder
# Set working directory
WORKDIR /app
# Copy all files from current directory to working dir in image
COPY . .
# install node modules and build assets
RUN yarn install && yarn build
# nginx state for serving content
FROM nginx:alpine
# Set working directory to nginx asset directory
WORKDIR /usr/share/nginx/html
# Remove default nginx static assets
RUN rm -rf ./*
# Copy static assets from builder stage
COPY --from=builder /app/build .
# Containers run nginx with global directives and daemon off
ENTRYPOINT ["nginx", "-g", "daemon off;"]
This works locally with docker.
I am using a T2.micro ec2 instance with a ecs cluster. The deployment of the service was successful and the task is running for the container image. I have tried going to the ec2 instance's public address and it returns took to long to respond. Let me know if you need any other details.
Thoughts?
I decided to go the route suggested by #David Maze and store it in an S3 bucket instead of using ECS for the website.
I followed this guide and it is working:
https://serverless-stack.com/chapters/deploying-a-react-app-to-aws.html

Where to run collectstatic when deploying django app to heroku using docker?

I am deploying a Django app to Heroku using Docker. When I put RUN manage.py collectstatic --noinput in the Dockerfile, it fails because there is no value set for the environment variable DJANGO_SECRET_KEY. My understanding is that this is because config vars aren't available during build time.
When I run collectstatic as a release command, it works without error, and successfully copies the static files. However, when I hit the app url, it returns a 500 error because the static files can't be found. I believe this is because the release command is run as a dyno on an ephemeral filesystem, and the copied files are therefore not found.
It seems to be a catch-22. Putting collectstatic in the Dockerfile fails because there are no config variables available, but putting it as a release command fails because only file changes from the build phase are saved?
What to do?
Here are my collectstatic settings in settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
...
]
...
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
STATICFILES_STORAGE = 'backend.storage.WhiteNoiseStaticFilesStorage'
Dockerfile
# Pull base image
FROM python:3.7-slim
# Set environment varibles
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set work directory
RUN mkdir /code
WORKDIR /code
# Install dependencies
RUN pip install pipenv
COPY Pipfile Pipfile.lock /code/
RUN pipenv install --system
# Copy project
COPY . /code/
## collect static files
RUN mkdir backend/staticfiles
# This fails because DJANGO_SECRET_KEY can't be empty
RUN python manage.py --noinput
heroku.yml
build:
docker:
web: Dockerfile
run:
web: gunicorn backend.config.wsgi:application --bind 0.0.0.0:$PORT
After confirming with Heroku support, this does indeed appear to be a bit of a catch-22.
The solution was to put collectstatic in the Dockerfile so that it runs during build time and the files persist.
We got around not having a secret key config var by setting a default secret key using the get_random_secret_key function from Django.
The run phase uses the secret key from the Heroku config vars, so we aren't actually changing the secret key every time -- the default only applies to the build process. collectstatic doesn't index on the secret key, so this is fine.
In settings.py
from django.core.management.utils import get_random_secret_key
...
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', default=get_random_secret_key())
I don't use heroku so can't test, but you should be able to run collect static before you run the app;
Dockerfile
# Pull base image
FROM python:3.7-slim
# Set environment varibles
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set work directory
WORKDIR /code/
# Install dependencies
RUN pip install pipenv
COPY Pipfile Pipfile.lock .
RUN pipenv install --system
# Copy project
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# run gunicorn
CMD gunicorn hello_django.wsgi:application --bind 0.0.0.0:$PORT
You could also not run collectstatic in your dockerfile, or event run the application because these can be ran by heroku.yml, for example;
build:
docker:
web: Dockerfile
config:
DJANGO_SETTINGS_MODULE: project.settings
run:
web: gunicorn backend.config.wsgi:application --bind 0.0.0.0:$PORT
release:
image: web
command:
- python manage.py collectstatic --noinput
You also shouldn't need to mkdir for your working directory. Just set WORKDIR /code/ early in your dockerfile and after that things will run based on that directory.
There's a decent article on this here; https://testdriven.io/blog/deploying-django-to-heroku-with-docker/
You can prefix commands with dummy environment variables
RUN DJANGO_SECRET_KEY=secret python manage.py collectstatic --no-input