I'm having a situation while setting up Django and all the dependencies I need with Docker (docker-toolbox, docker-compose).
I'm encountering an error while I'm trying to access to my url http://192.168.99.100:8000/ which says 502 Bad Gateway (nginx/1.13.1). For this error I don't really understand from where it comes since it's the first time I'm using Django with nginx on Docker.
docker-compose.yml :
version: '2'
services:
nginx:
image: nginx:latest
container_name: nz01
ports:
- "8000:8000"
volumes:
- ./src:/src
- ./config/nginx:/etc/nginx/conf.d
- /static:/static
depends_on:
- web
web:
...
...
Dockerfile :
FROM python:latest
ENV PYTHONUNBUFFERED 1
#ENV C_FORCE_ROOT true
ENV APP_USER myapp
ENV APP_ROOT /src
RUN mkdir /src;
RUN groupadd -r ${APP_USER} \
&& useradd -r -m \
--home-dir ${APP_ROOT} \
-s /usr/sbin/nologin \
-g ${APP_USER} ${APP_USER}
WORKDIR ${APP_ROOT}
RUN mkdir /config
ADD config/requirements.pip /config/
RUN pip install -r /config/requirements.pip
USER ${APP_USER}
ADD . ${APP_ROOT}
config/nginx/... .conf
upstream web {
ip_hash;
server web:8000;
}
server {
location /static/ {
autoindex on;
alias /static/;
}
location / {
proxy_pass http://web/;
}
listen 8000;
server_name localhost;
}
Is there something I'm doing wrong ?
The issue here is with gunicorn command line argument, missing -b flag. It needs to be launched with -b flag for binding with the address specified. In your case gunicorn binds itself to default 127.0.0.1:8000 which isn't accessible to other containers. So, just change the command for web to following:
command: bash -c 'python manage.py makemigrations && python manage.py migrate && gunicorn oqtor.wsgi -b 0.0.0.0:8000'
That should make your web app accessible via nginx.
Related
I have been trying for more than a week few hours daily.
Needless to say, I'm beginner in most of these things, but I have tried hundreds of configurations and nothing worked.
That's why I am finally coming here for help.
I am currently getting 502 Bad Gateway.
My suspicion is that either Nginx can't find staticfiles (if that's a reason for a 50x error) or nginx upstream doesn't know what is web (in config), or something with permissions on nginx.
Nginx error logs are printing this:
connect() failed (111: Connection refused) while connecting to upstream...upstream: "https://some-ip-address-here?:443" (this might be that nginx doesn't know about the web)
Dockerfile
# Pull base image
FROM python:3.10.2-slim-bullseye
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Create and set work directory called `app`
RUN mkdir -p /app
RUN mkdir -p /app/staticfiles
WORKDIR /app
# Install dependencies
COPY requirements.txt /tmp/requirements.txt
RUN set -ex && \
pip install --upgrade pip && \
pip install -r /tmp/requirements.txt && \
apt-get -y update && \
apt-get -y upgrade && \
apt-get install -y ffmpeg && \
rm -rf /root/.cache/
# Copy local project
COPY . /app/
COPY wait-for-it.sh /wait-for-it.sh
RUN chmod +x /wait-for-it.sh
docker-compose.yml
version: '3.7'
services:
web:
container_name: web
build: .
restart: always
command: ["/wait-for-it.sh", "db:5432", "--", "gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "my_project.wsgi"]
volumes:
- .:/app
ports:
- "8000:8000"
- "443"
env_file: .env
depends_on:
- db
nginx:
container_name: nginx
restart: always
image: jonasal/nginx-certbot:4.2.0-nginx1.23.3
env_file:
- .env.nginx
volumes:
- nginx_secrets:/etc/letsencrypt
- ./nginx/user_conf.d:/etc/nginx/user_conf.d
- .:/app
ports:
- 80:80
- 443:443
depends_on:
- web
- db
db:
container_name: db
image: postgres:13
restart: always
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file: .env
celery:
container_name: celery
restart: always
build:
context: .
command: celery -A my_project worker -l info -B
volumes:
- .:/app
env_file:
- .env
depends_on:
- web
- rabbitmq3
rabbitmq3:
container_name: rabbitmq
image: rabbitmq:3-management-alpine
ports:
- 5672:5672
- 15672:15672
volumes:
postgres_data:
nginx_secrets:
Nginx config
upstream web {
server web:443;
}
# Redirect all HTTP requests to HTTPS
server {
listen 80;
server_name myurl.com;
return 301 https://$server_name$request_uri;
location /static/ {
alias /app/staticfiles/;
}
location /media/ {
alias /app/media/;
}
}
# Pass request to the web container
server {
location / {
proxy_pass https://web/;
}
access_log /var/log/nginx/project.access.log;
error_log /var/log/nginx/project.error.log;
# Listen to port 443 on both IPv4 and IPv6.
listen 443 ssl default_server reuseport;
listen [::]:443 ssl default_server reuseport;
server_name www.myurl.com myurl.com;
# Load the certificate files
ssl_certificate /etc/letsencrypt/live/my-site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my-site/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/my-site/chain.pem;
# Load the Diffie-Hellman parameter
ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem;
location /static/ {
alias /app/staticfiles/;
}
location /media/ {
alias /app/media/;
}
}
I am building a Django app with Docker. I run the command collectstatic in my entrypoint when database is ready. When I check my container, the /static/ folder is empty. Thus, Nginx cannot load the static files.
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = '/static/'
Here is my docker-compose file
version: "3.9"
services:
db:
image: postgis/postgis:14-3.3
container_name: db
volumes:
- ./data/db:/var/lib/postgresql/data
env_file:
- prod.env
backend:
container_name: backend
build:
dockerfile: ./django/Dockerfile
command: gunicorn api.wsgi:application --bind 0.0.0.0:8000
volumes:
- static:/usr/src/app/static
ports:
- "8000:8000"
env_file:
- prod.env
depends_on:
- db
nginx:
container_name: nginx
build:
dockerfile: ./nginx/Dockerfile
volumes:
- static:/usr/src/app/static
ports:
- "80:80"
depends_on:
- backend
restart: always
redis:
container_name: redis
restart: unless-stopped
image: redis:alpine
expose:
- 6379
worker:
container_name: worker
build:
dockerfile: ./django/Dockerfile
command: celery -A api worker -l INFO
volumes:
- static:/usr/src/app/static
env_file:
- prod.env
depends_on:
- db
- backend
- redis
volumes:
static:
My Nginx configuration:
upstream api {
server backend:8000;
}
server {
listen 80;
location / {
proxy_pass http://api;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /usr/src/app/static/;
}
}
backend Dockerfile:
# syntax=docker/dockerfile:1
FROM python:3
WORKDIR /usr/src/app
RUN apt-get update
RUN apt-get install -y libgdal-dev gdal-bin netcat
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
COPY /django/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY /django/django-entrypoint.sh /django-entrypoint.sh
RUN chmod +x /django-entrypoint.sh
COPY django /usr/src/app
ENTRYPOINT ["/django-entrypoint.sh"]
And the entrypoint:
#!/bin/sh
if [ "$POSTGRES_NAME" = "postgres" ]
then
echo "Waiting for Postgres..."
while ! nc -z $POSTGRES_HOST $POSTGRES_PORT; do
sleep 0.1
done
echo "PostgreSQL started"
fi
ls
# python manage.py flush --no-input
python manage.py migrate --no-input
python manage.py collectstatic --no-input
exec "$#"
In my files (local), I do not seem to see the '/static/' folder to be generated. How is this? I have check that static in backend and nginx by ssh in the container and the static folders were empty. In the logs, collectstatic was executed without an error with this message:
backend | 173 static files copied to '/static'.
You use a Docker named volume to hold the static files
volumes:
- static:/usr/src/app/static
# ^^^^^^
# a volume name, not a host path
This named volume only exists inside Docker's storage; you will not see its content on your host system or in your local source tree.
This isn't a problem for the setup you're describing here: since you're re-running collectstatic every time the container starts up, and the volume contents hide the image contents in this directory, there's no particular need for the files to exist in source control or your host filesystem. If you did need them, you could presumably run manage.py collectstatic in a non-Docker virtual environment.
Try by adding the following command in Dockerfile and re-build image.
RUN python manage.py collectstatic --noinput
You can place it after RUN pip install --no-cache-dir -r requirements.txt
Good day, I am new to docker and I have a Django app I will like to dockerize, I have searched for tutorials to help me set up my Django app with docker, I followed this article here on test-driven https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/. I get issues making nginx work with my app. here is my code.
my apps docker file:
FROM python:3.8-alpine
ENV PATH="/scripts:${PATH}"
COPY ./requirements.txt /requirements.txt
RUN pip install -r /requirements.txt
RUN mkdir /app
COPY ./testdocker /app
WORKDIR /app
COPY ./scripts /scripts
RUN chmod +x /scripts/*
RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static
RUN adduser -D user
RUN chown -R user:user /vol
RUN chmod -R 755 /vol/web
USER user
nginx docker file:
FROM nginx:1.19.3-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx.conf /etc/nginx/conf.d
RUN mkdir -p /vol/static
my docker-compose file:
version: '3.7'
services:
app:
build:
context: .
command: sh -c "gunicorn testdocker.wsgi:application --bind 0.0.0.0:8000"
volumes:
- static_data:/vol/web
expose:
- "8000"
environment:
- SECRET_KEY=MANME1233
- ALLOWED_HOSTS=127.0.0.1, localhost
nginx:
build:
context: ./nginx
volumes:
- static_data:/vol/static
ports:
- "8080:80"
depends_on:
- app
volumes:
static_data:
my nginx conf file:
upstream testapp {
server app:8000;
}
server {
listen 8080;
server_name app;
location / {
proxy_pass http://testapp;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static {
alias /vol/static;
}
}
I can't seem to get nginx to reverse proxy to my web app, upon opening the URL on the browser I get a 404 bad request or address not found. please what am I doing wrong or not doing right?.
#victormazeli It looks like you missed placing your services within the same docker network and I see some misconfiguration in nginx conf file. Try updating your docker-compose.yml as follows:
version: '3.7'
services:
app:
build:
context: .
command: sh -c "gunicorn testdocker.wsgi:application --bind 0.0.0.0:8000"
volumes:
- static_data:/vol/web
expose:
- "8000"
environment:
- SECRET_KEY=MANME1233
- ALLOWED_HOSTS=127.0.0.1, localhost
networks:
- main
nginx:
build:
context: ./nginx
volumes:
- static_data:/vol/static
ports:
- "8080:80"
depends_on:
- app
networks:
- main
volumes:
static_data:
networks:
main:
Then, update your nginx config as follows:
server {
server_name nginx;
listen 80;
location /static {
alias /vol/static;
}
location / {
proxy_pass http://app:8000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Another thing to keep in mind here is that you have 2 targets that are being served by the NGINX reverse-proxy:
Django project located in testdocker which should be accessible via localhost:8080
Static file data which is accessible via localhost:8080/static/[relative_path]
To access the static data, you will need the path relative to /vol/static in nginx service (which is a docker volume mount also mounted to /vol/web in app service). According to app's Dockerfile, the static_data volume should contain 2 directories: media and static. Therefore, if you have say an index.html located in directory /vol/web/static in app service, it should be accessible via localhost:8080/static/static/index.html.
Give this a try and let me know how it works out for you.
I'm dockerizing a Django 2.x app
Dockerfile
FROM python:3-alpine
RUN apk --update add libxml2-dev libxslt-dev libffi-dev gcc musl-dev libgcc curl
RUN apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev postgresql-dev
RUN apk add --no-cache bash
ENV PYTHONUNBUFFERED 1
ENV LC_ALL C.UTF-8
ENV LANG C.UTF-8
RUN set -ex && mkdir /app
COPY Pipfile /app
COPY Pipfile.lock /app
WORKDIR /app
RUN pip install pipenv
RUN pipenv install --system --deploy
ADD . /app/
RUN chmod +x start.sh
RUN chmod +x wait-for-it.sh
EXPOSE 9010
docker-compose.yml
version: '3'
services:
nginx:
image: nginx:alpine
container_name: "originor-nginx"
ports:
- "10080:9010"
- "10443:43"
volumes:
- .:/app
- ./config/nginx:/etc/nginx/conf.d
- ./app/static_cdn/static_root:/app/static_cdn/static_root
- originor_media_volume:/app/static_cdn/media_root
depends_on:
- web
networks:
- originor_web_network
web:
build: .
container_name: "originor-web"
command: ["./wait-for-it.sh", "db:5432", "--", "./start.sh"]
volumes:
- .:/app
- ./app/static_cdn/static_root:/app/static_cdn/static_root
- originor_media_volume:/app/static_cdn/media_root
ports:
- "9010:9010"
depends_on:
- db
networks:
- originor_web_network
- originor_db_network
db:
image: postgres:11
container_name: "originor-postgres-schema"
volumes:
- originor_database:/var/lib/postgresql/data
networks:
- originor_db_network
env_file:
- config/db/originor_database.env
ports:
- "5432:5432"
networks:
originor_web_network:
driver: bridge
originor_db_network:
driver: bridge
volumes:
originor_database:
originor_static_volume:
originor_media_volume:
nginx.conf
error_log /var/log/nginx/error.log;
include /etc/nginx/conf.d/proxy.conf;
upstream web {
ip_hash;
server web:9010 fail_timeout=0;
}
server {
listen 10080;
server_name localhost;
access_log /var/log/nginx/localhost.access.log combined;
location /static/ {
autoindex on;
alias /app/static_cdn/static_root/;
}
location /media/ {
alias /app/static_cdn/media_root/;
}
location / {
proxy_pass http://web/;
}
}
The server is started using gunicorn
gunicorn --pythonpath src originor.wsgi:application \
--bind 0.0.0.0:9010 \
--workers 3
Since, nginx is listening to port 10080 and Django server is running on 9010.
When I visit http://localhost:10080 it does not load while visiting http://localhost:9010 is accessible.
There is no log in the docker-compose console regarding nginx.
Running command docker-compose logs nginx gives only
Attaching to originor-nginx
Use proxy_pass
location / {
proxy_pass http://web:10080/;
proxy_redirect off;
proxy_intercept_errors on;
proxy_next_upstream error timeout http_502 http_504;
}
I'm new to Docker and setting up my first Django application using Docker
My application path looks like
app
|- helloworld
|- __init__.py
|- manage.py
|- static_cdn
|- static_root
|- config
|- nginx
|- nginx.conf
|- Dockerfile
|- docker-compose.yml
|- requirements.txt
|- start.sh
the contents of Docerfile
FROM ubuntu:18.04
# -- Install Pipenv:
FROM python:3
ENV PYTHONUNBUFFERED 1
ENV LC_ALL C.UTF-8
ENV LANG C.UTF-8
# -- Install Application into container:
RUN set -ex && mkdir /app
WORKDIR /app
ADD requirements.txt /app/
RUN pip install -r requirements.txt
# -- Adding dependencies:
ADD . /app/
contents of docker-compose.yml
version: '3'
services:
nginx:
image: nginx:latest
ports:
- "9010:9010"
volumes:
- .:/app
- ./config/nginx:/etc/nginx/conf.d
- ./static_cdn:/static
depends_on:
- web
web:
build: .
command: ./start.sh
volumes:
- .:/app
- ./static_cdn:/static
ports:
- "9010:9010"
depends_on:
- db
expose:
- "9010"
db:
image: postgres
contents of config/nginx/nginx.conf
upstream web {
ip_hash;
server web:9010;
}
server {
location /static {
autoindex on;
alias /static/
}
location / {
proxy_pass http://127.0.0.1;
}
listen 9011;
server_name localhost;
}
contents of start.sh
#!/usr/bin/env bash
# Start Gunicorn processes
echo --: Starting application build
echo --: Creating migration
exec python3 manage.py makemigrations
echo ------: makemigrations complete
echo --: Running migration
exec python3 manage.py migrate
echo ------: migrate complete
echo --: Running collectstatic
exec python3 manage.py collectstatic
echo ------: collectstatic complete
echo Starting Gunicorn.
exec gunicorn helloworld.wsgi:application \
--bind 0.0.0.0:9010 \
--workers 3
Now, when I build using docker
docker-compose up --build
It gives error as
ERROR: for nginx Cannot start service nginx: driver failed
programming external connectivity on endpoint koober_nginx_1
(8ea5c084a7283a16afbf136a73dc4b27d9cae35fe14d735b83199ad5d0e03431):
Bind for 0.0.0.0:9010 failed: port is already allocated
I have followed few tutorials to create those Docker files and nginx conf file.
1. How can I solve above issue.
2. Do I need to use FROM ubuntu:18.04 with above configuration?
Edit 2
Now, it stuck after creating migration from start.sh commands
You can't allocate port 9010 of your host for both services.
This is what you're doing in the ports section of declaration of service nginx and web.
Moreover, by default nginx will listen to port 80 and 443 for https.
You can keep it like that and publish to a different port on your host. See how to use port keyword in docker-compose :
https://docs.docker.com/compose/compose-file/#ports
Maybe you want something more like that:
version: '3'
services:
nginx:
image: nginx:latest
ports:
- "10080:80"
- "10443:443"
volumes:
- .:/app
- ./config/nginx:/etc/nginx/conf.d
- ./static_cdn:/static
depends_on:
- web
web:
build: .
command: ./start.sh
container_name: "web-app"
volumes:
- .:/app
- ./static_cdn:/static
expose:
- "9010"
depends_on:
- db
db:
image: postgres
contents of config/nginx/nginx.conf
upstream web {
ip_hash;
server web-app:9010;
}
server {
location /static {
autoindex on;
alias /static/
}
location / {
proxy_pass http://web;
}
listen 80;
server_name localhost;
}
Concerning your last question, you could go for an official Python image from the Docker hub Python repository or start from any other base image like debian:jessie-slim from Debian official repository or keep the Ubuntu 18.04 image
For me, stopping/restarting the NGINX server worked.
To stop Nginx, use the following command:
sudo systemctl stop nginx
To start Nginx when it is stopped, use the following command:
sudo systemctl start nginx
To restart Nginx, use the following command:
sudo systemctl restart nginx
To reload Nginx after making configuration changes, use the following command:
sudo systemctl reload nginx