# ASGI/WSGI with Channels Behind Nginx - Is my app even running?

**URL:** <https://forum.djangoproject.com/t/asgi-wsgi-with-channels-behind-nginx-is-my-app-even-running/38825>\
**Category:** Async/Channels\
**Created:** [February 13, 2025, 4:08pm UTC](https://forum.djangoproject.com/t/asgi-wsgi-with-channels-behind-nginx-is-my-app-even-running/38825 "2025-02-13T16:08:49Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![cory5643](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/cory5643/32/26902_2.png) [@cory5643](https://forum.djangoproject.com/u/cory5643)\
**Post date:** [February 13, 2025, 4:08pm UTC](https://forum.djangoproject.com/t/asgi-wsgi-with-channels-behind-nginx-is-my-app-even-running/38825/1 "2025-02-13T16:08:49Z")

</div>

Hi,

I am a beginner learning more about deploying Django projects with async components. I have a small grasp of a good architecture from this discussion, and am looking to learn the mechanics.

> [@Understanding a dev/production channels/async setup with daphne and uvicorn](https://forum.djangoproject.com/t/understanding-a-dev-production-channels-async-setup-with-daphne-and-uvicorn/24259):
>
> Hello, Long time Django user but relatively short-time user of async tech here. I’m setting up an asynchronous app with websockets for the first time in a long time. I’d like to: Use daphne in development, for the great runserver integration. Use uvicorn in production, because I’m already using gunicorn. Apart from a high-level question of “is this a sensible setup?” I’m also wondering what to do with Daphne in production. Does keeping the library around and the “daphne” app in INSTALLED\_APP…

So, I have a dockerfile:

```auto
FROM --platform=linux/amd64 python:3.10.4-slim-bullseye

ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

COPY ./requirements.txt .

RUN pip install -r requirements.txt

COPY ./scripts /scripts
RUN chmod -R +x /scripts

ENV PATH="/scripts:/py/bin:$PATH"

COPY ./app /app

EXPOSE 8000 8001

```

ASGI:

```auto
import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "scopist.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.

django_asgi_app = get_asgi_application()

from transcript.routing import websocket_urlpatterns

application = ProtocolTypeRouter(
    {
        "http": django_asgi_app,
        "websocket": AllowedHostsOriginValidator(
            AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
        ),
    }
)

```

I have a docker-compose yaml file:

```auto
services:

  app_wsgi:
      build:
        context: .
      command: gunicorn scopist.wsgi:application --bind 127.0.0.1:8000
      volumes:
        - ./app:/app
        - dev-app-data:/vol/app
      depends_on:
        db:
          condition: service_healthy
      environment:
        - DJANGO_DEBUG=true
        - DJANGO_SECRET_KEY=django-insecure-$65qwith0x$0%w-sm+%92rt-j#t8-pdyt7a$+j-o7#1iv&te&z
        - DB_HOST=db
        - DB_NAME=postgres
        - DB_USER=postgres
        - DB_PASSWORD=postgres

  app_asgi:
    build:
      context: .
    command: daphne -b 0.0.0.0 -p 8001 scopist.asgi:application
    volumes:
      - ./app:/app
      - dev-app-data:/vol/app
    environment:
      - DJANGO_DEBUG=true
      - DJANGO_SECRET_KEY=django-insecure-$65qwith0x$0%w-sm+%92rt-j#t8-pdyt7a$+j-o7#1iv&te&z
      - DB_HOST=db
      - DB_NAME=postgres
      - DB_USER=postgres
      - DB_PASSWORD=postgres
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:13
    volumes:
      - dev-db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    healthcheck:
      test: ["CMD", "pg_isready", "-q", "-d", "postgres", "-U", "postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d
    depends_on:
      - app_wsgi
      - app_asgi

volumes:
  dev-db-data:
  dev-app-data:

```

And an NGINX conf:

```auto
worker_processes 1;

events {
    worker_connections 1024;
}

http {
    upstream asgi_backend {
        server app_asgi:8001;
    }

    upstream wsgi_backend {
        server app_wsgi:8000;
    }

    # For WebSocket support
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    server {
        listen 80;
        server_name localhost;

        # Route WebSocket requests (e.g., those starting with /ws/) to ASGI container
        location /ws/ {
            proxy_pass http://asgi_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
        }

        # Route all other requests to the WSGI container
        location / {
            proxy_pass http://wsgi_backend;
            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-Proto $scheme;
        }
    }
}

```

I’m not quite sure what the logs are telling me:

NGINX:

```auto
2025-02-12 23:45:34 /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
2025-02-12 23:45:34 /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
2025-02-12 23:45:34 /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
2025-02-12 23:45:34 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist
2025-02-12 23:45:34 /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
2025-02-12 23:45:34 /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
2025-02-12 23:45:34 /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
2025-02-12 23:45:34 /docker-entrypoint.sh: Configuration complete; ready for start up
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: using the "epoll" event method
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: nginx/1.27.4
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: built by gcc 14.2.0 (Alpine 14.2.0) 
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: OS: Linux 6.12.5-linuxkit
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker processes
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 20
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 21
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 22
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 23
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 24
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 25
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 26
2025-02-12 23:45:34 2025/02/13 06:45:34 [notice] 1#1: start worker process 27

```

WSGI container:

```auto
2025-02-12 23:45:34 [2025-02-13 06:45:34 +0000] [1] [INFO] Starting gunicorn 23.0.0
2025-02-12 23:45:34 [2025-02-13 06:45:34 +0000] [1] [INFO] Listening at: http://127.0.0.1:8000 (1)
2025-02-12 23:45:34 [2025-02-13 06:45:34 +0000] [1] [INFO] Using worker: sync
2025-02-12 23:45:34 [2025-02-13 06:45:34 +0000] [7] [INFO] Booting worker with pid: 7

```

ASGI:

```auto
2025-02-12 23:45:46 2025-02-13 06:45:46,956 INFO Starting server at tcp:port=8001:interface=0.0.0.0
2025-02-12 23:45:46 2025-02-13 06:45:46,957 INFO HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2025-02-12 23:45:46 2025-02-13 06:45:46,958 INFO Configuring endpoint tcp:port=8001:interface=0.0.0.0
2025-02-12 23:45:46 2025-02-13 06:45:46,960 INFO Listening on TCP address 0.0.0.0:8001

```

In sum, everything seems to have been built ok, and I’m not seeing any obvious errors. But now I have no idea how to run my app. I have been messing around with ports and IPs and localhosts, and I can’t get anything to actually run.

Sorry for the dumb question, but what am I missing?

Thanks.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [February 13, 2025, 5:37pm UTC](https://forum.djangoproject.com/t/asgi-wsgi-with-channels-behind-nginx-is-my-app-even-running/38825/2 "2025-02-13T17:37:40Z")

</div>

Welcome @cory5643 !

Have you tried pointing your browser at your Nginx instance? What happens when you try to request a page?

Note, you should:

- Read [How to deploy Django](https://docs.djangoproject.com/en/5.1/howto/deployment/)
- Read (and do) the [Deployment checklist](https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/)
- Create an nginx location for your `static` directory (and `media` if appropriate)
- Run `collectstatic`
- Run `migrate` (You don’t need to do a makemigrations - that should have been done earlier)

---

<div class="post-metadata">

**Author:** ![cory5643](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/cory5643/32/26902_2.png) [@cory5643](https://forum.djangoproject.com/u/cory5643)\
**Post date:** [February 20, 2025, 4:14am UTC](https://forum.djangoproject.com/t/asgi-wsgi-with-channels-behind-nginx-is-my-app-even-running/38825/3 "2025-02-20T04:14:24Z")

</div>

Hi @KenWhitesell - thanks for the kind welcome.

I want to close the loop on this issue. I started from scratch and rewrote some scripts. I had some typos and needed to put some work into static files and migrations - just as you suggested. I now have a perfectly running app with WSGI and ASGI components, dockerized and with NGINX directing traffic.

Onward to (Kubernetes and) deployment.

Thanks again!
