I am trying to set up my Django Rest Framework application. Unfortunately I still can't manage to get the media files url right.
I tried adding the lines from this answer to my nginx configuration ending up with "Bad Request (400)": Django Rest framework swagger base url
The application is running on my-domain.com.
https://my-domain.com/user/
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "512e0f9f-f08a-4a2d-8e1d-b933a16c0a1f",
"date_joined": "2021-10-10T11:41:05.077828Z",
"name": "Maxine Mustermann",
"user_picture": "**http://127.0.0.1:8337**/mediafiles/images/usr1.jpeg"
}
]
}
Expected: https://my-domain.com/mediafiles/images/usr1.jpeg (Eventhough the picture can be accessed with this url)
Returned: http://127.0.0.1:8337/mediafiles/images/usr1.jpeg
docker-compose file:
version: "3.8"
services:
db:
image: postgres:13-alpine
volumes:
- postgres_data_staging:/var/lib/postgresql/data/
env_file:
- ./.env.staging.db
expose:
- 5432
web:
build:
context: ./api
dockerfile: Dockerfile.staging
command: gunicorn config.wsgi:application --workers 3 --bind 0.0.0.0:8000
volumes:
- static_volume_staging:/home/api/web/staticfiles
- media_volume_staging:/home/api/web/mediafiles
expose:
- 8000
env_file:
- ./.env.staging
depends_on:
- db
nginx:
build: ./nginx
volumes:
- static_volume_staging:/home/api/web/staticfiles
- media_volume_staging:/home/api/web/mediafiles
ports:
- 8337:80
depends_on:
- web
volumes:
postgres_data_staging:
static_volume_staging:
media_volume_staging:
nginx.conf:
upstream ae_backend {
server web:8000;
}
server {
listen 80;
client_max_body_size 75M;
server_name $DOMAIN www.$DOMAIN;
location / {
proxy_pass http://ae_backend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
location /staticfiles/ {
alias /home/api/web/staticfiles/;
}
location /mediafiles/ {
alias /home/api/web/mediafiles/;
}
}
Server configuration nginx/sites-enabled/my-api:
server {
server_name my-domain.com;
location = /favicon.ico { access_log off; log_not_found off; }
# add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization';
location / {
proxy_pass http://127.0.0.1:8337;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/my-domain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/my-domain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = my-domain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name my-domain.com;
return 404; # managed by Certbot
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization';
}
Any help and reference will be appreciated.
Thank you!!
Regards,
Florian
btw: This is my first post on stackoverflow. Please be nice ;-)
I edited this part into my Server nginx config:
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:8337;
}
and made sure that my-domain.com ist listed in the "ALLOWED_HOSTS" (settings.py).
Related
i hope that u can help me.
I deployed my django application to an ubuntu 20.04 server with nginx and gunicorn.
This is my settings:
gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/var/www/PlugSell
ExecStart=/var/www/PlugSell/env/bin/gunicorn --access-logfile - --error-logfile - -k uvicorn.workers.UvicornWorker --workers 3 --bind unix:/run/gunicorn.sock minible.asgi:application
[Install]
WantedBy=multi-user.target
app nginx conf
server {
server_name 3.73.206.145 127.0.0.1 sell.plug-shop.com;
location = /favicon.ico {
access_log off; log_not_found off;
}
location /static/ {
root /var/www/PlugSell;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
location /ws/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Url-Scheme $scheme;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://unix:/run/gunicorn.sock;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/sell.plug-shop.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/sell.plug-shop.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = sell.plug-shop.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name 3.73.206.145 127.0.0.1 sell.plug-shop.com;
return 404; # managed by Certbot
}
in settings.py i have
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 6379)],
},
},
}
and in my asgi.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'minible.settings')
django.setup()
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
[
path('ws/notification/',
consumer.NotificationConsumer.as_asgi())
]
)
)
})
Redis is installed and work perfectly (binding at 0.0.0.0)
Everything works perfectly but the websocket doesn't work.
I try to connect to the websocket via "wss://sell.plug-shop.com/ws/notification/" but the connection always fails. In the nginx log file it does not give me any information regarding some connection error to the websocket
I have a Django server which uses websockets (Django channels). I have the following configurations of daphne and nginx.
What the right way to configure ngnix for wss websockets?
Here's what I have:
/etc/nginx/sites-available/trading-backend
server {
server_name trading-backend-test.myserver.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
alias /home/vagram/trading-backend/static_root/;
}
location /media/ {
alias /home/vagram/trading-backend/media_root/;
}
location /ws/ {
proxy_pass http://unix:/home/vagram/run/daphne.sock;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/vagram/trading-backend.sock;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/trading-backend-test.myserver.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/trading-backend-test.myserver.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = trading-backend-test.myserver.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name trading-backend-test.myserver.com;
return 404; # managed by Certbot
}
/etc/systemd/system/daphne.socket
[Unit]
Description=daphne socket
[Socket]
ListenStream=/run/daphne.sock
[Install]
WantedBy=sockets.target
/etc/systemd/system/daphne.service
Description=WebSocket Daphne Service
Requires=daphne.socket
After=network.target
[Service]
Type=simple
User=vagram
WorkingDirectory=/home/vagram/trading-backend/src
ExecStart=/home/vagram/trading-backend/env/bin/daphne -b 0.0.0.0 -p 8001 project.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
I am using Apache on CentOS. On this server I have a Django project with docker. There are two containers in docker (nginx and python).
In the Apache I have .conf that have proxy to nginx container that is exposed on port 803. SSL is set in the Apache conf as well.
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Scheme "https"
ProxyPass / http://127.0.0.1:803/
ProxyPassReverse / http://127.0.0.1:803/
On the docker I have app.conf for nginx that looks like this:
upstream project {
server project-python:5000;
}
server {
listen 80;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 64M;
location / {
gzip_static on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Scheme "https";
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header X-Forwarded-Protocol "ssl";
proxy_set_header X-Forwarded-Ssl=on;
proxy_set_header Host $host;
proxy_pass http://project;
proxy_redirect off;
}
}
In the Dockerfile Python is exposed on port 5000 and in the docker-compose.prod.yml file for production the python is started with gunicorn with this command:
gunicorn project.wsgi:application --preload --bind 0.0.0.0:5000
So I have two issues.
In the Django when I dump request.META I got wsgi.url_scheme that is http.
The second one is that I don't even understand how nginx is communicating with gunicorn because when I set app.conf to be just like below it is working also. How the nginx know that Python is exposed on port 5000.
server {
listen 80;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 64M;
location / {
proxy_pass http://project;
proxy_redirect off;
}
}
docker-compose.yml
version: '3'
services:
project-python:
build:
context: .
dockerfile: docker/python/Dockerfile
container_name: project-python
volumes:
- .:/var/www:rw
- .aws:/home/www/.aws
project-nginx:
build:
context: docker/nginx
dockerfile: Dockerfile
container_name: project-nginx
ports:
- "127.0.0.1:803:80"
depends_on:
- project-python
docker-compose.prod.yml
version: '3'
services:
project-python:
restart: unless-stopped
env_file:
- ./.env.prod
command: gunicorn project.wsgi:application --preload --bind 0.0.0.0:5000
expose:
- 5000
project-nginx:
restart: unless-stopped
environment:
APP_ENV: "production"
APP_NAME: "project-nginx"
APP_DEBUG: "False"
SERVICE_NAME: "project-nginx"
I'm working with Docker, Nginx and Django. I would like to secure my application with ssl but it won't work.
I got a valid certificate using certbot
This is my nginx.conf file:
upstream app {
server app:80;
}
server {
listen 80;
listen [::]:80;
server_name mydomain.de;
return 301 https://$server_name$request_uri;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/certbot;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mydomain.de;
ssl_certificate /etc/nginx/ssl/live/mydomain.de/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/mydomain.de/privkey.pem;
location / {
proxy_pass https://app;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Host $host;
# proxy_redirect off;
}
location /staticfiles/ {
alias /app/staticfiles/;
add_header Access-Control-Allow-Origin *;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/certbot;
}
}
}
That's my docker-compose file:
version: '3.4'
services:
app:
image: django
build:
context: ./app
dockerfile: Dockerfile
env_file:
- ./.env
volumes:
- ./app/:/app/
- ./app/staticfiles/:/app/staticfiles
command: gunicorn --bind 0.0.0.0:8000 --chdir /app/ Webserver.wsgi
nginx:
build: ./nginx
ports:
- 80:80
- 433:433
depends_on:
- app
volumes:
- ./app/staticfiles/:/app/staticfiles
- ./certbot/conf:/etc/nginx/ssl
- ./certbot/data:/var/www/certbot
db:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
POSTGRES_DB_PORT: "5432"
POSTGRES_DB_HOST: "myhost"
POSTGRES_PASSWORD: "mypw"
POSTGRES_USER: myname
POSTGRES_DB: dev_db
volumes:
postgres_data:
If I try to access my Website I just see the browser message "Connection refused"
I renamed sensitive information like domain name and passwords
Below I'm providing a working certbot nginx configuration example:
server {
# show half the users an optimized site, half the regular site
listen 80;
gzip on;
gzip_http_version 1.0;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 9;
gzip_disable "MSIE [1-6]\.";
gzip_types text/plain text/xml text/css
text/comma-separated-values
text/javascript
application/x-javascript
application/atom+xml;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# side note: only use TLS since SSLv2 and SSLv3 have had recent vulnerabilities
access_log /var/www/vhosts/mydomain.de/logs/access_log;
error_log /var/www/vhosts/mydomain.de/logs/error_log;
server_name 3dact.com www.mydomain.de;
location ~* .+.>(xml|jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|swf) {
access_log off;
expires 30d;
break;
}
charset utf-8;
root /var/www/vhosts/mydomain.de/public/dist;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
# what to serve if upstream is not available or crashes
error_page 500 502 503 504 /media/50x.html;
location ~* .+.>(xml|jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|swf) {
root /var/www/vhosts/mydomain.de/public/dist;
access_log off;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
break;
}
location /dist {
alias /var/www/vhosts/mydomain.de/public/dist;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/nginx/ssl/live/mydomain.de/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/nginx/ssl/live/mydomain.de/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.mydomain.de) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = mydomain.de) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name mydomain.de www.mydomain.de;
return 404; # managed by Certbot
}
The first server block provides the actual locations and certbot configurations, the second one is used by certbot for domain redirections (www.). Given you properly map the volumes in docker-compose.yml, that should preserve the consistency when you're connecting. Also, make sure ports 80 and 443 get proper exposure outside of the container.
In your docker-compose.yml:
nginx:
build: ./nginx
ports:
- 80:80
- 433:433
depends_on:
- app
volumes:
- ./app/staticfiles/:/app/staticfiles
- ./certbot/conf:/etc/nginx/ssl # Make sure it maps into /etc/nginx/ssl/live/mydomain.de
- ./certbot/data:/var/www/certbot
- ./letsencrypt:/etc/letsencrypt # This is where options-ssl-nginx.conf and ssl-dhparams.pem are located
If you don't have a local ./letsencrypt dir or the files are located in a different place, please create any dirs, copy the files there and configure the mapping accordingly.
I've created simple example for dockerized django with nginx and gunicorn. But for some reason connection doesn't go through nginx.
Here is nginx.conf contents
worker_processes 1;
error_log /var/log/nginx/error.log info;
events {
worker_connections 1024;
}
http {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 2;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name www.example.dj example.dj;
location = /favicon.ico {
alias /app/static_root/favicon.ico;
}
location /static/ {
alias /app/static_root/;
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unix:/app/example.sock;
}
}
}
docker-compose.yml file
version: '3'
services:
web:
build: .
hostname: web
command: bash -c "python manage.py migrate && gunicorn example.wsgi:application --workers 3 --bind unix:/app/example.sock"
volumes:
- ./src:/app
expose:
- "8000"
nginx:
image: nginx:latest
ports:
- "80:8000"
volumes:
- ./src:/app
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web
In /etc/hosts I have
127.0.0.1 www.example.dj example.dj
So when I run docker-compose up I expect to see django start page by http://example.dj url, but there is no connection. Can you guys help me with it?
Code available on the github