UPDATE:
It may be closed, remember to always check code copied from outside... The problem was with quote marks in Daphne Service
I want to deploy my Django app (Rest API + React on frontend) on AWS. I use nginx, gunicorn (for http handling) and daphne (for async websockets - Im using django channels for chat application). I was following THIS tutorial.
It looks like I configured well nginx and gunicorn (page is normally loading, I can handle sync request to rest API) but I guess there are some problems with daphne and/or asgi. I use systemctl services for server. All 3 (nginx, gunicorn, daphne) statuses show 'active'. Everything works fine on my development server on local.
On deployment server when I enter website, I see in console
Firefox can’t establish a connection to the server at ws://PATH_TO_WEBSOCKET
Is Daphne connected well with Nginx?
I use Redis for CHANNEL_LAYERS. I have installed channels-redis and redis-server on Ubuntu server. I think it works fine as I get respond
> redis-cli
> ping
**PONG**
project tree
.
├── frontend #react files
├── checkers #project dir
│ ├── settings.py
│ ├── urls.py
│ └── asgi.py
├── chat #chat app
│ ├── consumers.py
│ └── routing.py
└── checkers.sock
asgi.py
import os
import django
from channels.routing import get_default_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'checkers.settings')
django.setup()
application = get_default_application()
settings.py
ROOT_URLCONF = 'checkers.urls'
ASGI_APPLICATION = "checkers.routing.application"
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
daphne service worker
[Unit]
Description=My Daphne Service
After=network.target
[Service]
Type=simple
User=ams
Group=www-data
WorkingDirectory=/home/ams/production_app
ExecStart=/home/ams/production_app/production_env/bin/daphne --access-log /home/ams/production_app/log/daphne-access.log -b 0.0.0.0 -p 9001 checkers.asgi:application
[Install]
WantedBy=multi-user.target
Nginx config file at /etc/nginx/sites-available/ (our websockets endpoints start with /ws/)
upstream channels-backend {
server 0.0.0.0:9001;
}
server {
listen 80;
server_name MY_SERVER;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/ams/production_app;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/ams/production_app/checkers.sock;
}
location /ws/ {
proxy_pass http://channels-backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_redirect off;
proxy_set_header Host $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;
}
}
Related
I am trying to connect a secure websocket WSS with Redis/Daphne from my Django-Project:
new WebSocket('wss://myproject.com:9002/ws/myChat/')
But it is not possible to connect. In the Browser-Console I always get the following error:
myCode.js:36 WebSocket connection to 'wss://myproject.com:9002/ws/myChat/' failed
This is the only error I see, e.g. Nginx (sudo tail -F /var/log/nginx/error.log) shows no related error.
The Daphne and Redis-Services seem to work:
Redis Status:
redis-server.service - Advanced key-value store
Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-07 08:44:07 CEST; 55min ago
Docs: http://redis.io/documentation,
man:redis-server(1)
Process: 281 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS)
Main PID: 381 (redis-server)
Tasks: 4 (limit: 60)
Memory: 4.1M
CGroup: /system.slice/redis-server.service
└─381 /usr/bin/redis-server 127.0.0.1:6379
Daphne-Service Config:
[Unit]
Description=WebSocket Daphne Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/home/django_user/appdir/myProject
ExecStart=/home/django_user/appdir/env/bin/python3 /home/django_user/appdir/env/bin/daphne -e ssl:9002:privateKey=/etc/letsencrypt/live/myproject.com/privkey.pem:certKey=/etc/letsencrypt/myproject.com/fullchain.pem myproject.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
Daphne-Service Status:
daphne_myproject.service - WebSocket Daphne Service
Loaded: loaded (/etc/systemd/system/daphne_myproject.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-07 08:44:04 CEST; 50min ago
Main PID: 277 (python3)
Tasks: 1 (limit: 60)
Memory: 74.8M
CGroup: /system.slice/daphne_myproject.service
└─277 /home/django_user/appdir/env/bin/python3 /home/django_user/appdir/env/bin/daphne -e ssl:9002:privateKey=/etc/letsencrypt/live/myproject.com/privkey.pem:certKey=/etc/letsencrypt/live/myproject.com/fullchain.pem myproject.asgi:application
Nginx-Config:
upstream websocket{
server 127.0.0.1:6379;
}
server {
server_name myproject.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/django_user/appdir/myProject;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/myproject.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/myproject.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
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $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;
}
}
server {
if ($host = myproject.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name myproject.com;
return 404; # managed by Certbot
}
And in my Django-Project:
settings.py
ASGI_APPLICATION = "myproject.routing.application"
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
routing.py: (in the chat-app, which is part of my Django-project, the wss://myproject... websocket is opened)
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
asgi.py:
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()
Did I miss something here? I am trying now for days but can't figure out where the problem could be. Could it be because I use the root user for the Daphne service and not django_user? I did that because django_user could not access my certificates in /etc/letsencrypt/... (though he has sudo rights).
Update:
Just saw this error (at sudo systemctl status daphne_myproject.service):
Apr 07 19:42:07 myproject.com python3[268]: 2022-04-07 19:42:07,215 ERROR Exception inside application: Django can only handle ASGI/HTTP connections, not websocket.
I just solved my problem by modifying asgi.py as follows. Maybe it will help someone else with the same problem:
import os
import django
from channels.routing import get_default_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
application = get_default_application()
I have a setup with Nginx as web server and Gunicorn as application server serving a Django REST API.
Nginx is listening at port 80 and gunicorn at port 8000 (I launch gunicorn using this command):
gunicorn --bind 0.0.0.0:8000 cdm_api.wsgi -t 200 --workers=3
and when I launch the petition to port 8000, I am able to access to the API running for instance:
curl -d "username=<user>&password=<pass>" -X POST http://127.0.0.1:8000/api/concept
However, when I try to make the petition though Nginx acting as reverse proxy, I get 404 Not Found Error:
curl -d "username=<user>&password=<pass>" -X POST http://127.0.0.1:80/api/concept
Here is my nginx conf file:
server {
listen 80;
listen [::]:80;
server_name 127.0.0.1;
location /api/ {
proxy_pass http://127.0.0.1:8000/api/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 360s;
proxy_read_timeout 360s;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
Let me know if more information is needed. Thanks in advance!
So
gunicorn will create a sock file and you will have to map your proxy_pass with the sock file created, for now you are mapping to your localhost:8000 for this you will have to run the django runserver command so that nginx can find a server running on port 8000.
something like -
location / {
include proxy_params;
#proxy_pass http://unix:/home/abc/backend/social.sock;
proxy_pass http://unix:/home/abc/backend/backend.sock;
}
gunicorn make it possible to serve django at production, you don't have to command runserver everytime. Make sure gunicorn restarts everytime when server reboots.
Having an issue using secure websocket (wss) with django, Nginx, Gunicorn, and daphne. My site is hosted through cloudflare which provides the SSL/TLS certificate. I'm using a linux socket in /run/daphne/daphne.sock, where I gave the user 'ubuntu' ownership of the daphne folder.
The websockets work fine locally when it is not secured. When I tried hosting on my EC2 instance, I get the error-
sockets.js:16 WebSocket connection to 'wss://www.mywebsite.com/ws/sheet/FPIXX8/' failed:
Then it keeps trying to reconnect and fail again. It never sets up an initial connection since I don't get a ping.
Here are a few relevant files and snippets of code-
settings.py
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer', # asgi_redis.RedisChannelLayer ?
'CONFIG': {
'hosts': [('localhost', 6379)],
},
}
}
I think there may be an issue with the 'hosts' but I haven't been able to figure out through tutorials/googling, nor am I sure exactly what it does besides set a port. Since I'm using sockets, I imagine this would need to be different (or maybe it's ignored?) in deployment.
Routing.py (in main project dir)
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import app.routing
application = ProtocolTypeRouter({
# (http->django views is added by default)
'websocket': AuthMiddlewareStack(
URLRouter(
app.routing.websocket_urlpatterns
)
),
})
Routing.py (in app)
from django.urls import re_path
from django.conf.urls import url
from app import consumers
websocket_urlpatterns = [
re_path(r'ws/sheet/(?P<gameID>\w+)/$', consumers.GameConsumer.as_asgi()),
]
I'm pretty sure neither routing.py files don't cause an issue because I still get redirected properly.
asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = get_asgi_application()
I haven't touched this file.
Javascript
if (window.location.protocol == 'https:') {
wsProtocol = 'wss://'
} else {wsProtocol = 'ws://'}
updateSocket = new WebSocket(
wsProtocol + window.location.host +
'/ws/sheet/' + game_ID + '/');
This also seems to work fine, since I get redirected and it attempts to connect to proper URL with wss://.
systemd/system/daphne.service
[Unit]
Description=project Daphne Service
After=network.target
[Service]
User=ubuntu
Type=simple
WorkingDirectory=/home/ubuntu/django/project/project
ExecStart=/home/ubuntu/django/project/project/virtualenv/bin/daphne \
-u /run/daphne/daphne.sock \
project.asgi:application
[Install]
WantedBy=multi-user.target
systemd/system/daphne.socket
[Unit]
Description=daphne socket
[Socket]
ListenStream=/run/daphne/daphne.sock
[Install]
WantedBy=sockets.target
nginx
server {
listen 80;
server_name www.mywebsite.com mywebsite.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/ubuntu/django/project/project/;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
location /ws/ {
proxy_pass http://unix:/run/daphne/daphne.sock;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_redirect off;
proxy_set_header Host $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;
}
}
WantedBy=sockets.target
I should probably add running 'sudo nginx -t' to get errors does not return any errors. Running 'sudo journalctl -u daphne' usually would not return errors, but I just checked again and I got another Permission Denied error at '/run/daphne/daphne.sock.lock' which I thought was fixed, so I tried to give permission again. Then, I got a 'Address already in use' for the daphne.sock. So, I restarted all services and now it just says 'Configuring endpoint unix:/run/daphne/daphne.sock' as the latest message, so I don't know if that is good or bad.
I am trying to run django + gunicorn + nginx locally.
For some reason nginx is not getting data from static. Please tell me what am I doing wrong?
Gunicorn:
gunicorn config.wsgi:application --bind 127.0.0.1:8001
Nginx config:
# mysite_nginx.conf
upstream project_server {
server 127.0.0.1:8001;
}
# the upstream component nginx needs to connect to
# configuration of the server
server {
# the port your site will be served on
listen 80;
# the domain name it will serve for
server_name localhost; # substitute your machine's IP address or FQDN
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias /home/ferom/Programming/my_avatar_clock/media; # your Django project's media files - amend as required
}
location /static {
alias /home/ferom/Programming/my_avatar_clock/my_avatar_clock/proj/static; # your Django project's static files - amend as required
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
}
}
Folders:
In settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
But when I open http://127.0.0.1/admin/
Nginx say me: 404.
cat /var/log/nginx/error.log - empty
What am I doing wrong?
Maybe you unicorn port was not the same on the Nginx file. I recommend you try set the same port, on the Gunicorn and Nginx proxy.
you say that Gunicorn command was on port 8001:
gunicorn config.wsgi:application --bind 127.0.0.1:8001
But you nginx file was proxy on port 8000:
proxy_pass http://127.0.0.1:8000;
Iam new to nginx.
I have configured nginx,gunicorn and django.
when i start nginx, it gives an error as,
404 Not Found
nginx/1.1.19
as it is not pointing to django.
Now i need to point out nginx to django(using gunicorn as middleware) in conf file using location or root.
Can anyone tell me how to point out nginx to django.
Thank you
I've got many Apps running like this:
server {
# listen, statics, media, etc
location / {
proxy_pass http://127.0.0.1:8000; # Gunicorn Server
}
}
First, you need to actually have the gunicorn process running. Do this either manually, or ideally using a process management tool such as supervisord. Here's a sample supervisord script that runs a gunicorn process on a django project:
[program:example]
user=ubuntu
group=ubuntu
directory=/home/ubuntu/dev/example
command=python manage.py run_gunicorn -c gunicorn_config.py
autostart=true
autorestart=true
redirect_stderr=True
Then you need a proper nginx conf. Here's a minimal sample based off a site running in production:
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
server_name example.com;
location / {
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# use this if you're serving static assets locally
location /static/ { # make sure this is your STATIC_ROOT
alias /home/ubuntu/dev/example/static/;
access_log off;
}
}