Deploying dockerized Django with channels + Nginx + Daphne

Viewed 1610

i have a django application, running in Docker, which is using channels 2 (for a chat app). When running docker-compose up on local, the site and websocket chat works like a charm.

Now i tried to deploy the project: I want to run the whole project only on ASGI with daphne (instead of Daphne for Websocket and gunicorn for standard requests). Well, i tried it for three days now, i dont get it working. I am completey lost.

The website with "standard" http requests over https is working perfect, the chat with websockets gives me a 500 error, but the error message is a miracle to me. I have really no idea, what to do next.

(have to say, i am a beginner in django, nginx and websockets)

My setup is: Django, Django Channels, Redis, Nginx, Docker, Daphne

Django Projectname is xtools

This is my production docker-compose:

version: '3.7'

services:
  web:
    container_name: 'web'
    build: 
      context: ./app
      dockerfile: Dockerfile.prod
    command: daphne -b 0.0.0.0 -p 8000 xtools.asgi:application
    volumes:
      - static_volume:/home/app/web/static
      - media_volume:/home/app/web/mediafiles
    expose:
      - 8000
    env_file:
      - ./.env.prod
    depends_on:
      - db
    networks:
      - docker-network

  redis:
    image: redis:latest
    command: ["redis-server", "--bind", "redis", "--port", "6379"]

  db:
    image: postgres:12.0-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    env_file:
      - ./.env.prod.db
    networks:
      - docker-network
  nginx:
    build: ./nginx
    volumes:
      - static_volume:/home/app/web/staticfiles
      - media_volume:/home/app/web/mediafiles
      - ./dhparam/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem
      - /docker-volumes/etc/letsencrypt/live/example.com/fullchain.pem:/etc/letsencrypt/live/example.com/fullchain.pem
      - /docker-volumes/etc/letsencrypt/live/example.com/privkey.pem:/etc/letsencrypt/live/example.com/privkey.pem
      - /docker-volumes/data/letsencrypt:/data/letsencrypt
    ports:
      - 80:80
      - 443:443
    depends_on:
      - web
    networks:
      - docker-network

volumes:
  postgres_data:
  static_volume:
  media_volume:

networks:
  docker-network:
    driver: bridge

This is my nginx conf:

upstream toolbox {
    server web:8000;
}


proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=tool_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name xtools.com;

        server_tokens off;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        ssl_buffer_size 8k;

        ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;

        ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
        ssl_prefer_server_ciphers on;

        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

        ssl_ecdh_curve secp384r1;
        ssl_session_tickets off;

        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8;


        location /ws/ {
            try_files $uri @proxy_to_ws;
        }

        location @proxy_to_ws {
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_redirect off;

            proxy_pass   http://toolbox;
        }

        location / {
            proxy_pass http://toolbox;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_cache tool_cache;
            proxy_cache_valid any 48h;


            add_header X-Cached $upstream_cache_status;

            # Simple requests
            if ($request_method ~* "(GET|POST)") {
              add_header "Access-Control-Allow-Origin"  *;
            }

        }

        location /static/ {
            alias /home/app/web/staticfiles/;
        }

        location /mediafiles/ {
            alias /home/app/web/mediafiles/;
        }

}

And this is the error msg:

2020-04-08 14:40:11,802 ERROR    Exception inside application: [Errno -2] Name does not resolve
File "/usr/local/lib/python3.8/site-packages/channels/sessions.py", line 183, in __call__
  return await self.inner(receive, self.send)
File "/usr/local/lib/python3.8/site-packages/channels/middleware.py", line 41, in coroutine_call
  await inner_instance(receive, send)
File "/usr/local/lib/python3.8/site-packages/channels/consumer.py", line 58, in __call__
  await await_many_dispatch(
File "/usr/local/lib/python3.8/site-packages/channels/utils.py", line 58, in await_many_dispatch
  await task
File "/usr/local/lib/python3.8/site-packages/channels_redis/core.py", line 434, in receive
  message_channel, message = await self.receive_single(
File "/usr/local/lib/python3.8/site-packages/channels_redis/core.py", line 489, in receive_single
  content = await self._brpop_with_clean(
File "/usr/local/lib/python3.8/site-packages/channels_redis/core.py", line 330, in _brpop_with_clean
  async with self.connection(index) as connection:
File "/usr/local/lib/python3.8/site-packages/channels_redis/core.py", line 835, in __aenter__
  self.conn = await self.pool.pop()
File "/usr/local/lib/python3.8/site-packages/channels_redis/core.py", line 73, in pop
  conns.append(await aioredis.create_redis(**self.host, loop=loop))
File "/usr/local/lib/python3.8/site-packages/aioredis/commands/__init__.py", line 168, in create_redis
  conn = await create_connection(address, db=db,
File "/usr/local/lib/python3.8/site-packages/aioredis/connection.py", line 111, in create_connection
  reader, writer = await asyncio.wait_for(open_connection(
File "/usr/local/lib/python3.8/asyncio/tasks.py", line 455, in wait_for
  return await fut
File "/usr/local/lib/python3.8/site-packages/aioredis/stream.py", line 23, in open_connection
  transport, _ = await get_event_loop().create_connection(
File "/usr/local/lib/python3.8/asyncio/base_events.py", line 978, in create_connection
  infos = await self._ensure_resolved(
File "/usr/local/lib/python3.8/asyncio/base_events.py", line 1350, in _ensure_resolved
  return await loop.getaddrinfo(host, port, family=family, type=type,
File "/usr/local/lib/python3.8/asyncio/base_events.py", line 817, in getaddrinfo
  return await self.run_in_executor(
File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
  result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.8/socket.py", line 914, in getaddrinfo
  for res in _socket.getaddrinfo(host, port, family, type, proto, flags):

Redis tells me, that's running

redis_1  | 1:M 08 Apr 2020 14:37:56.433 * Ready to accept connections

Daphne is accepting connections, the website works as mentioned before:

web      | 2020-04-08 14:38:01,587 INFO     Starting server at tcp:port=8000:interface=0.0.0.0
web      | 2020-04-08 14:38:01,588 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
web      | 2020-04-08 14:38:01,589 INFO     Configuring endpoint tcp:port=8000:interface=0.0.0.0
web      | 2020-04-08 14:38:01,590 INFO     Listening on TCP address 0.0.0.0:8000
web      | 2020-04-08 14:38:05,597 ERROR    Exception inside application: [Errno -2] Name does not resolve

I have no idea, where this "Name does not resolve" belong to. My Consumer-Code works perfect in my local environment. In production the consumer is not even called (i put a lot of print-statements in it, just to see, if there's an error maybe somewhere).

Nginx Error Logs keeps repeating this error, when opening the chat page with websockets:

2020/04/08 17:36:12 [emerg] 18725#18725: bind() to 0.0.0.0:80 failed (98: Address already in use)
 25 2020/04/08 17:36:12 [emerg] 18725#18725: still could not bind()
 26 2020/04/08 17:36:17 [notice] 18736#18736: signal process started
 27 2020/04/08 17:36:20 [notice] 18741#18741: signal process started

My Websocket Client Call

var ws_scheme = window.location.protocol == "https:" ? "wss://" : "ws://";
var chatSocket = new ReconnectingWebSocket(
        ws_scheme + window.location.host +
        '/ws/chat/' + roomName + '/'
        );

what else can i do? I tested the redis server, that works. Daphne is running and serving pages, as it should.

Any help is appreciated! Thanks Bombi

0 Answers
Related