Setting up sockets with Django on gninx
<p>I have a Django application running on nginx. This application use sockets, which (as far as I know) should be proxied. So I have troubles configuring nginx and other stuff. Same application works fine on Apache/2.4.7, so I assume that it is not a programming mistake.</p>

<p>Sockets using is based on Django-Channels and backend is very similar to code from <a href="https://channels.readthedocs.io/en/latest/getting-started.html" rel="nofollow">Channels getting started</a>.</p>

<p>For server configuration I used <a href="https://media.readthedocs.org/pdf/django-websocket-redis/latest/django-websocket-redis.pdf" rel="nofollow">this</a> manual.</p>

<p>In the beginning I had just one problem: I got 200 request answer instead of 101 on socket creation. After many manipulations (configuring and newer versions installing) and information collecting I came to current situation:</p>

<p>I start uwsgi separately for sockets:</p>

<pre><code>uwsgi --virtualenv /home/appname/env/ --http-socket /var/run/redis/redis.sock --http-websock --wsgi-file /home/appname/appname/appname/wsgi.py
</code></pre>

<p>On this step on socket creation <code>var socket = new WebSocket("ws://appname.ch/ws/64");</code> I get </p>

<pre><code>WebSocket connection to 'ws://appname.ch/ws/64' failed: Error during WebSocket handshake: Unexpected response code: 502 
</code></pre>

<p>and sure </p>

<pre><code>2016/09/12 12:00:26 [crit] 30070#0: *2141 connect() to unix:/var/run/redis/redis.sock failed (13: Permission denied) while connecting to upstream, client: 140.70.82.220, server: appname.ch,, request: "GET /ws/64 HTTP/1.1", upstream: "http://unix:/var/run/redis/redis.sock:/ws/64", host: "appname.ch"
</code></pre>

<p>in nginx error log.</p>

<p>After <code>chmod 777 /var/run/redis/redis.sock</code> I get responce</p>

<pre><code>WebSocket connection to 'ws://appname.ch/ws/64' failed: Error during WebSocket handshake: Unexpected response code: 404
</code></pre>

<p>and in uwsgi</p>

<pre><code>[pid: 6572|app: 0|req: 1/1] 0.0.0.0 () {46 vars in 916 bytes} [Mon Sep 12 12:01:29 2016] GET /ws/64 =&gt; generated 3357 bytes in 24 msecs (HTTP/1.1 404) 2 headers in 80 bytes (1 switches on core 0)
</code></pre>

<p>nginx.conf file</p>

<pre><code>user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
worker_connections 768;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;
gzip_disable "msie6";

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
</code></pre>

<p>redis.conf</p>

<pre><code>daemonize yes

pidfile /var/run/redis/redis-server.pid

port 6379

unixsocket /var/run/redis/redis.sock
unixsocketperm 777

timeout 0

loglevel notice

logfile /var/log/redis/redis-server.log

databases 16

save 900 1
save 300 10
save 60 10000

rdbcompression yes

dbfilename dump.rdb

dir /var/lib/redis

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
</code></pre>

<p>/etc/nginx/sites-enabled/appname </p>

<pre><code>server {
        listen       80;
        server_name  appname.ch, 177.62.206.170;

      #charset koi8-r;
    client_max_body_size 8M;

        access_log  /var/log/nginx/access.log;
        error_log   /var/log/nginx/error.log;

        location / {
            include        uwsgi_params;
            uwsgi_pass     unix:///home/appname/appname/app.sock;
           #add_header     Access-Control-Allow-Origin *;
    }
    location /ws/ {
        #proxy_redirect off;
        proxy_pass http://unix:/var/run/redis/redis.sock;
        #proxy_http_version 1.1;
        #proxy_set_header Upgrade $http_upgrade;
            #proxy_set_header Connection "upgrade";

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

    }

        location /static {
            alias /home/appname/appname/static_files;
        }

        location /media {
            alias /home/appname/appname/media;
       }
}
</code></pre>

<p>uwsgi.ini</p>

<pre><code>[uwsgi]

chdir=/home/appname/appname
env=DJANGO_SETTINGS_MODULE=appname.settings
wsgi-file=appname/wsgi.py
master=True
pidfile=/home/appname/appname/appname-master.pid
vacuum=True
max-requests=5000
daemonize=/home/appname/appname/uwsgi.log
socket=/home/appname/appname/app.sock
virtualenv=/home/appname/env
uid=appname
gid=appname
</code></pre>

<p>Django app settings.py</p>

<pre><code>"""
Django settings for appname project.

For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ''

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = DEBUG

ALLOWED_HOSTS = ['.appname.ch', '177.62.206.170', '127.0.0.1']


# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'customers',
    'projects',
    'moodboard',
    'channels',
    'debug_toolbar',
    'rest_framework',
    'appname',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'appname.urls'

WSGI_APPLICATION = 'appname.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/

STATIC_URL = '/static/'

MEDIA_URL = '/media/'

STATIC_ROOT = os.path.join(BASE_DIR, 'static_root')

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static_files'),
)

TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'templates'),
)

AUTH_PROFILE_MODULE = 'customers.Customer'

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

LOGIN_REDIRECT_URL = '/accounts/home'

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "asgi_redis.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("localhost", 6379)],
        },
        "ROUTING": "appname.routing.channel_routing",
    },
}
</code></pre>

<p>App urls</p>

<pre><code>from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.contrib.auth import views as auth_views
from projects.views import ProjectViewSet
from customers.views import UserHomeView, RegistrationView, CustomerViewSet, UserViewSet
from moodboard.views import MoodBoardViewSet, BoardItemViewSet, BoardTextViewSet, ShareMoodBoardItem, LiveViewSet
from rest_framework import routers
from django.conf import settings
from django.conf.urls.static import static


router = routers.DefaultRouter()
router.register(r'projects', ProjectViewSet)
router.register(r'moodboards', MoodBoardViewSet)
router.register(r'items', BoardItemViewSet)
router.register(r'texts', BoardTextViewSet)
router.register(r'share', ShareMoodBoardItem)
router.register(r'customers', CustomerViewSet)
router.register(r'users', UserViewSet)
router.register(r'live', LiveViewSet)


urlpatterns = patterns('',
                       url(r'^$', 'appname.views.home', name='landing_page'),
                       url(r'^api/', include(router.urls)),
                       url(r'^accounts/login/$', auth_views.login, name='login'),
                       url(r'^accounts/logout/$', auth_views.logout, name='logout'),
                       url(r'^accounts/home/$', UserHomeView.as_view(), name='home'),
                       url(r'^accounts/register/$', RegistrationView.as_view(), name='registration'),
                       url(r'^admin/', include(admin.site.urls)),
                       url(r'^customers/', include('customers.urls')),
                       url(r'^projects/', include('projects.urls')),
                       url(r'^moodboard/', include('moodboard.urls')),
                       url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
                       )

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)root
</code></pre>

<p><code>nginx version: 1.6.2
Redis server version: 2.4.14
uwsgi version: 2.1
Django version: 1.8.0 'final'
Python version: 2.7.3
</code></p>

<p>Seems 404 should not be a complicated error, but after many days of fixing I have no idea what the problem is and if I am on the right way generally. </p>

<p>First of all, do not ever try to create sock manually. 
Just set up a path, and it will be created automatically. </p>

<p>This is example nginx and uwsgi conf:</p>

<pre><code>server {
root /your/djang/app/main/folder/;

# the port your site will be served on
listen      80;
server_name your-domain.com *.your-domain.com # if you have subdomains
charset     utf-8;

access_log /path/to/logs/if/you/have/access_log.log
error_log /path/to/logs/if/you/have/error_log.log

# max upload size
client_max_body_size 1G;

location /media/  {
    alias /path/to/django/media/if/exist/;
}

location /static/ {
    alias  /path/to/django/static/if/exist/;
}
# Note three slash 
location / { 
    uwsgi_pass unix:///home/path/to/sock/file/your-sock.sock
}
</code></pre>

<p>}</p>

<p>and this cna be your uwsgi config file</p>

<pre><code># suprasl_uwsgi.ini file
[uwsgi]

uid = www-data
gid = www-data
chmod-socket = 755
chown-socket = www-data
# Django-related settings
# the base directory (full path)
chdir           = /your/djang/app/main/folder/
# Django's wsgi file
wsgi-file       = /your/djang/app/main/folder/main-folder/wsgi.py;
# the virtualenv (full path)
home            = /your/env/folder/;
# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 2
# the socket (use the full path to be safe
socket          =  /home/path/to/sock/file/your-sock.soc

logto           = /path/to/logs/if/you/have/uwsgi_logs.log
</code></pre>

<p>All you have to do is just run this command:</p>

<p><code>uwsgi --ini your_uwsgi_file.ini</code> # the --ini option is used to specify a file</p>

python django sockets nginx redis