Prior to gunicorn and nginx, i’ve tried to user apache + mod_wsgi and failed. Still don’t know why it fail. After 3 days trying, I give up. I have to look for another method, I try using gunicorn dan nginx, and It took me only 2 days for gunicord + nginx setup to works. 🙂
Here is condition on my Django + Gunicorn + Nginx setup:
- I use CentOS 7 on my server
- I create new user for running django (in my case /home/myuser)
- I install python 3.7.3, django, pandas, django_extensions, virtual environment, gunicorn dan nginx
- My django project folder is /home/myuser/myproject
- I put all my django app (created using ‘python manage.py startapp myapp apps/myapp’) in /home/myuser/myproject/apps
Here is some of reference I use:
Here is my setup:
/home/myuser/myproject/wsgi.py
import os
import sys
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
sys.path.append('/home/myuser/myproject/apps')
application = get_wsgi_application()
/etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
/etc/systemd/system/gunicorn.service
setup for gunicorn to be run as service.
[Unit]
Description=gunicorn service
After=network.target
[Service]
User=myuser
Group=myuser
WorkingDirectory=/home/myuser/myproject/
ExecStart=/home/myuser/app1/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/myuser/myproject/myproject.sock myproject.wsgi:application --log-level debug
[Install]
WantedBy=multi-user.target
don’t forget to enable service using:
systemctl enable gunicorn
/home/myuser/myproject/myproject/setting.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = '6sp(_!o*NOT_MY_REAL_KEY_OF_COURSE*uu5o(9q1+ir=:-)r' # change: my key
DEBUG = True # to be changed on production
ALLOWED_HOSTS = ['my_ip','myuser.mydomain.com'] #change: my_ip & my domain
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
'django_extensions',
'myproject',
'myproject.templatetags', # delete:my custom tags
'login', # delete:my app
'weeklyreport', # delete:my app
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['my_templates'], #change
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'myproject.wsgi.application'
DATABASES = {
'default': { #change: my database setup
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb1',
'USER': 'myuseruser',
'PASSWORD': 'my_db_password',
'HOST': '192.168.0.2',
'OPTIONS': {
'read_default_file': '/etc/my.cnf.d/client.cnf',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'; SET SESSION binlog_format = 'ROW';",
},
'jgmotordb': { #delete: my database setup
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb2', #change
'USER': 'myuseruser', #change
'PASSWORD': 'my_db_password', #change
'HOST': 'my_ip', # change
'OPTIONS': {
'read_default_file': '/etc/my.cnf.d/client.cnf',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'; SET SESSION binlog_format = 'ROW';",
}
}
}
}
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/' # my static folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, '0static'), # my static folder (before for 'collectstatic' command)
]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
AUTHENTICATION_BACKENDS = ( 'myproject.backend.custombackend', ) #delete: my custom backends
It’s my django project. Therefor, you might find my setup is not ideal, but it works! 🙂 (and it took me a week to make it works).
I learn that, most of tutorials use apt / apt-get for installation. Since I use CenOS (which use yum as default) I find it annoying. 😦
Please leave a comment for any suggestion or if you find this post helpful.