Sample NGINX config files

Many times NGINX conf reference comes handy. Here I am copying couple of NGINX conf setups for future reference.

Single WordPress

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        #server_name _;
        server_name example.com www.example.com;

        location / {
                #try_files $uri $uri/ =404;
                #try_files $uri/ index.php$args;
	        try_files $uri /index.php$is_args$args;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;

                # With php7.0-cgi alone:
                #fastcgi_pass 127.0.0.1:9000;
                # With php7.0-fpm:
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }

	location /wp-admin/ {
		index index.php;
		try_files $uri $uri/ /index.php$args;
	}
}

WordPress multi site

Please not the additional details at top and before closing bracket of server block. For installation of multiple please check post How to Install WordPress Multisite

map $http_host $blogid {
    default 0;
    include /var/www/yourwebsite/wp-content/uploads/nginx-helper/map.conf;
}

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        #server_name _;
        server_name example.com www.example.com;

        location / {
                #try_files $uri $uri/ =404;
                #try_files $uri/ index.php$args;
	        try_files $uri /index.php$is_args$args;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;

                # With php7.0-cgi alone:
                #fastcgi_pass 127.0.0.1:9000;
                # With php7.0-fpm:
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }

	location /wp-admin/ {
		index index.php;
		try_files $uri $uri/ /index.php$args;
	}
	
	location ~ ^/files/(.*)$ {
	  try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ;
	  access_log off; log_not_found off; expires max;
	}

	location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
		expires 24h;
		log_not_found off;
	}

	location ^~ /blogs.dir {
		internal;
		alias /var/www/fintrekking/wp-content/blogs.dir ;
		access_log off; log_not_found off;      expires max;
	}


	if (!-e $request_filename) {
		rewrite /wp-admin$ $scheme://$host$uri/ permanent;
		rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
		rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;
	}
	
}

Installing NGINX on Ubuntu

First you need to update the Ubuntu and then simply run sudo apt install as below

sudo apt update

When NGINX is installed it will create a folder called as /www inside /var/ directory in Ubuntu. Here is how folders look like before installation

/var$ ll
total 52
drwxr-xr-x 13 root root 4096 Apr 30 23:26 ./
drwxr-xr-x 19 root root 4096 Jun 15 14:39 ../
drwxr-xr-x 2 root root 4096 Apr 15 2020 backups/
drwxr-xr-x 12 root root 4096 Jun 15 14:40 cache/
drwxrwxrwt 2 root root 4096 Apr 30 23:25 crash/
drwxr-xr-x 38 root root 4096 Jun 15 14:39 lib/
drwxrwsr-x 2 root staff 4096 Apr 15 2020 local/
lrwxrwxrwx 1 root root 9 Apr 30 23:15 lock -> /run/lock/
drwxrwxr-x 9 root syslog 4096 Jun 15 14:39 log/
drwxrwsr-x 2 root mail 4096 Apr 30 23:15 mail/
drwxr-xr-x 2 root root 4096 Apr 30 23:15 opt/
lrwxrwxrwx 1 root root 4 Apr 30 23:15 run -> /run/
drwxr-xr-x 6 root root 4096 Apr 30 23:36 snap/
drwxr-xr-x 4 root root 4096 Apr 30 23:17 spool/
drwxrwxrwt 6 root root 4096 Jun 15 14:39 tmp/

Please note there is no /www directory as we have not installed NGINX yet. Please note that, if you have any other server such as apache in install, /www will already be there.
Now let us install NGINX.

sudo apt install nginx
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libgd3 libjbig0 libjpeg-turbo8 libjpeg8 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream libtiff5 libwebp6
  libxpm4 nginx-common nginx-core
Suggested packages:
  libgd-tools fcgiwrap nginx-doc ssl-cert
The following NEW packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libgd3 libjbig0 libjpeg-turbo8 libjpeg8 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream libtiff5 libwebp6
  libxpm4 nginx nginx-common nginx-core
0 upgraded, 17 newly installed, 0 to remove and 60 not upgraded.
Need to get 2431 kB of archives.
After this operation, 7891 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://us-west-1.ec2.archive.ubuntu.com/ubuntu focal/main amd64 fonts-dejavu-core all 2.37-1 [1041 kB]
Get:2 http://us-west-1.ec2.archive.ubuntu.com/ubuntu focal/main amd64 fontconfig-config all 2.13.1-2ubuntu3 [28.8 kB]
Get:3 http://us-west-1.ec2.archive.ubuntu.com/ubuntu focal/main amd64 libfontconfig1 amd64 2.13.1-2ubuntu3 [114 kB]
Get:4 http://us-west-1.ec2.archive.ubuntu.com/ubuntu focal-updates/main amd64 libjpeg-turbo8 amd64 2.0.3-0ubuntu1.20.04.1 [117 kB]
Get:5 http://us-west-1.ec2.archive.ubuntu.com/ubuntu focal/main amd64 libjpeg8 amd64 8c-2ubuntu8 [2194 B]
......
Setting up libnginx-mod-stream (1.18.0-0ubuntu1.2) ...
Setting up libtiff5:amd64 (4.1.0+git191117-2ubuntu0.20.04.1) ...
Setting up libfontconfig1:amd64 (2.13.1-2ubuntu3) ...
Setting up libgd3:amd64 (2.2.5-5.2ubuntu2) ...
Setting up libnginx-mod-http-image-filter (1.18.0-0ubuntu1.2) ...
Setting up nginx-core (1.18.0-0ubuntu1.2) ...
Setting up nginx (1.18.0-0ubuntu1.2) ...
Processing triggers for ufw (0.36-6) ...
Processing triggers for systemd (245.4-4ubuntu3.6) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.2) ...

After installation /www will be created. Here is how it looks like after installation

var$ ll
total 56
drwxr-xr-x 14 root root 4096 Jun 15 14:42 ./
drwxr-xr-x 19 root root 4096 Jun 15 14:39 ../
drwxr-xr-x 2 root root 4096 Apr 15 2020 backups/
drwxr-xr-x 12 root root 4096 Jun 15 14:40 cache/
drwxrwxrwt 2 root root 4096 Apr 30 23:25 crash/
drwxr-xr-x 39 root root 4096 Jun 15 14:42 lib/
drwxrwsr-x 2 root staff 4096 Apr 15 2020 local/
lrwxrwxrwx 1 root root 9 Apr 30 23:15 lock -> /run/lock/
drwxrwxr-x 10 root syslog 4096 Jun 15 14:42 log/
drwxrwsr-x 2 root mail 4096 Apr 30 23:15 mail/
drwxr-xr-x 2 root root 4096 Apr 30 23:15 opt/
lrwxrwxrwx 1 root root 4 Apr 30 23:15 run -> /run/
drwxr-xr-x 6 root root 4096 Apr 30 23:36 snap/
drwxr-xr-x 4 root root 4096 Apr 30 23:17 spool/
drwxrwxrwt 6 root root 4096 Jun 15 14:39 tmp/
drwxr-xr-x 3 root root 4096 Jun 15 14:42 www/

NGINX registers itself as a service with ufw after installation.

$ sudo ufw app list
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH

Let us allow traffic using NGINX HTTP by using following command

$sudo ufw allow 'Nginx HTTP'
Rules updated
Rules updated (v6)

Finally just to ensure NGINX is running file, you can check the status using following command

$ sudo service nginx status
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-06-15 14:42:10 UTC; 2min 35s ago
Docs: man:nginx(8)
Main PID: 2030 (nginx)
Tasks: 2 (limit: 1160)
Memory: 5.3M
CGroup: /system.slice/nginx.service
├─2030 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─2031 nginx: worker process

Jun 15 14:42:10 ip-172-31-7-66 systemd[1]: Starting A high performance web server and a reverse proxy server...
Jun 15 14:42:10 ip-172-31-7-66 systemd[1]: Started A high performance web server and a reverse proxy server.

other commands.

$sudo service nginx status
$sudo service nginx start
$sudo service nginx stop
$sudo service nginx restart
$sudo service nginx reload
$sudo service nginx disable
$sudo service nginx enable

Now you can access your server and it will display below page

Hope this is helpful. Please let me know if you have any query or getting any unexpected error.

Getting Started with django with ubuntu

Tag line for django says “The web framework for perfectionists with deadlines.” and most would agree. django is rediculously fast to implement, its fully loaded with lots of utilitis, its secure and at the same time its highly scalable. some of the most popular sites like instagram, pinterest are built with django.

Let us get our hands dirty by getting started with django instead of talking about django features.

Which django version should I use ?

Here are the details about djnago release. you can choose latest version, however, I will stick with LTS version

Currently I am using Django 2.2 for most of my projects.

Which Python version should I use ?

This is the most common question and following table with clarify your query

Django version Python versions
  1.11 2.7, 3.4, 3.5, 3.6
  2.0 3.4, 3.5, 3.6, 3.7
  2.1,2.2 3.5, 3.6, 3.7

In this tutorial we are going to use python version 3.6 (3.6.4 to be very specifuc) and django version 1.11.

Install django version 1.11

$ sudo python3.6 -m pip install django==1.11
Collecting django==1.11
Downloading https://files.pythonhosted.org/packages/47/a6/078ebcbd49b19e22fd560a2348cfc5cec9e5dcfe3c4fad8e64c9865135bb/Django-1.11-py2.py3-none-any.whl (6.9MB)
100% |████████████████████████████████| 6.9MB 339kB/s 
Requirement already satisfied: pytz in /usr/local/lib/python3.6/site-packages (from django==1.11) (2017.3)
Installing collected packages: django
Successfully installed django-1.11

You can check the version as below

$ python3.6 -m django --version
1.11

Creating django project

$ django-admin startproject mysite

Now CD into directory “mysite” and run following command

$python3.6 manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).

You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

July 18, 2018 - 17:43:11
Django version 1.11, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[18/Jul/2018 17:43:31] "GET / HTTP/1.1" 200 1716
Not Found: /favicon.ico

Now you can access django website at location http://127.0.0.1:8000/

here is the output

Creating application

Now that your environment – a “project” – is set up, you’re set to start doing work.

$ python3.6 manage.py startapp polls

after creating polls app, please add following code to polls/views.py


from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

Now create a file urls.py and add following code


from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

Now add following code in mysite.urls.py


from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', admin.site.urls),
]

Here is the output

Hope this is helpful…

Troubleshooting django web application deployed using NGINX, uWSGI errors

For any type of error, first check if UWSGI is running fine ?

myusername@ubuntu-512:~$ sudo service uwsgi status
● uwsgi.service - uWSGI Emperor
   Loaded: loaded (/etc/systemd/system/uwsgi.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-09-09 08:39:27 IST; 9min ago
  Process: 1451 ExecStartPre=/bin/bash -c mkdir -p /run/uwsgi; chown myusername:www-data /run/uwsgi (code=exited, status=0/SUCCESS)
 Main PID: 1530 (uwsgi)
   Status: "The Emperor is governing 3 vassals"
    Tasks: 7
   Memory: 142.7M
      CPU: 1.874s
   CGroup: /system.slice/uwsgi.service
           ├─1530 /usr/local/bin/uwsgi --emperor /home/myusername/uwsgi/sites
           ├─1564 /usr/local/bin/uwsgi --ini website1.ini
           ├─1565 /usr/local/bin/uwsgi --ini website2.ini
           ├─1625 /usr/local/bin/uwsgi --ini website3.ini
           ├─2022 /usr/local/bin/uwsgi --ini website3.ini
           ├─2033 /usr/local/bin/uwsgi --ini website2.ini
           └─2035 /usr/local/bin/uwsgi --ini website1.ini

Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: Input to details english quote We-accept-the-love-we-think-we-deserve.
Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: context: success
Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: context: post_type quote
Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: [pid: 2033|app: 0|req: 7/7] 114.119.146.195 () {40 vars in 768 bytes} [Wed Sep  9 03:14:29 2020] GET
Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: [pid: 2035|app: 0|req: 1/1] 93.158.161.64 () {38 vars in 515 bytes} [Wed Sep  9 03:14:29 2020] GET /
Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: announcing my loyalty to the Emperor...
Sep 09 08:44:29 ubuntu-512 uwsgi[1530]: Wed Sep  9 08:44:29 2020 - [emperor] vassal website1.ini is now loyal
Sep 09 08:46:03 ubuntu-512 uwsgi[1530]: [pid: 2035|app: 0|req: 2/2] 114.119.145.68 () {40 vars in 748 bytes} [Wed Sep  9 03:16:03 2020] GET 
Sep 09 08:49:09 ubuntu-512 uwsgi[1530]: --- no python application found, check your startup logs for errors ---
Sep 09 08:49:09 ubuntu-512 uwsgi[1530]: [pid: 2022|app: -1|req: -1/5] 49.35.75.185 () {46 vars in 692 bytes} [Wed Sep  9 03:19:09 2020] GET

You might see any error here. In above log its showing error as --- no python application found, check your startup logs for errors ---. In this case, we need to check the wsgi.py file settings. Your wsgi file should look something like below. Please not the lines where I have added comment #added this

import os
import sys #added this

from django.core.wsgi import get_wsgi_application

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #added this
sys.path.append(BASE_DIR) #added this

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourapp.settings')

application = get_wsgi_application()

 

Another way to trouble shoot is to check if .sock is created at following location

/run/uwsgi

If nothing gives any clue, try to see if you can run application manually using following command

sudo uwsgi --http 0.0.0.0:8400 --home /var/www/mywebsite1/venvft --chdir /var/www/mywebsite1/mysite07 --wsgi-file /var/www/mywebsite1/mysite07/wsgi.py

You might get different error here. e.g. some library is not installed. I got an error that model requests not found. I installed it in virtualenv as below

$virtualenv venvft
created virtual environment CPython3.6.4.final.0-64 in 453ms
creator CPython3Posix(dest=/var/www/yourapp/venvft, clear=False, global=False)
seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/home/user/.local/share/virtualenv/seed-app-data/v1.0.1)
activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

$source venvft/bin/activate
$pip install django 
$pip install psycopg2
$pip install requests
deactivate

Another error I got is as below

*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 72920 bytes (71 KB) for 1 cores
*** Operational MODE: single process ***
Traceback (most recent call last):
  File "/var/www/website3/mysite07/wsgi.py", line 19, in 
    application = get_wsgi_application()
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/core/wsgi.py", line 12, in get_wsgi_application
    django.setup(set_prefix=False)
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/apps/registry.py", line 91, in populate
    app_config = AppConfig.create(entry)
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/apps/config.py", line 116, in create
    mod = import_module(mod_path)
  File "/usr/local/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "", line 994, in _gcd_import
  File "", line 971, in _find_and_load
  File "", line 955, in _find_and_load_unlocked
  File "", line 665, in _load_unlocked
  File "", line 678, in exec_module
  File "", line 219, in _call_with_frames_removed
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/contrib/auth/apps.py", line 8, in 
    from .checks import check_models_permissions, check_user_model
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/contrib/auth/checks.py", line 8, in 
    from .management import _get_builtin_permissions
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/contrib/auth/management/__init__.py", line 9, in 
    from django.contrib.contenttypes.management import create_contenttypes
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/contrib/contenttypes/management/__init__.py", line 2, in 
    from django.db import (
  File "/var/www/website3/venvft/lib/python3.6/site-packages/django/db/migrations/__init__.py", line 1, in 
    from .migration import Migration, swappable_dependency  # NOQA
ModuleNotFoundError: No module named 'django.db.migrations.migration'
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 2699, cores: 1)

Here if you see in details, error is with the migrations. In above screen error is ModuleNotFoundError: No module named 'django.db.migrations.migration' common solution is to reinstall django. Here fortunately we are using virtualenv so I can remove and reinstall it without impacting other applications

$rm -rf venvft
$virtualenv venvft
created virtual environment CPython3.6.4.final.0-64 in 453ms
creator CPython3Posix(dest=/var/www/yourapp/venvft, clear=False, global=False)
seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/home/user/.local/share/virtualenv/seed-app-data/v1.0.1)
activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

$source venvft/bin/activate
$pip install django 
$pip install psycopg2
pip install requests
deactivate

once its done I rerun the following

sudo uwsgi --http 0.0.0.0:8400 --home /var/www/mywebsite1/venvft --chdir /var/www/mywebsite1/mysite07 --wsgi-file /var/www/mywebsite1/mysite07/wsgi.py

Here again I got below error

sFatal Python error: Py_Initialize: Unable to get the locale encoding
ModuleNotFoundError: No module named 'encodings'

Current thread 0x00007f7b5b79d700 (most recent call first):
Aborted (core dumped)

however when I tried to access my website, it was working properly. so for now, I decided to ignore the error

django QuerySet examples

If you want to fetch whole table or if you want to fetch n number of rows (lets try 30 in current case)

context = MyModel.objects.all()
context = MyModel.objects.all()[:30]
## You can iterate over the output as well 
for e in MyModel.objects.all():
      print(e.headline)

if you want to fetch data in specific order. – sign indicates descending

context = MyModel.objects.all().order_by('pub_date')
context = MyModel.objects.all().order_by('-pub_date')

Filtering

(name__startswith='Beatles')
#like clause
filter(name__contains='Smith')
Product.objects.filter(name__search='Shiny')

exluding

 context = MyModel.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

if you want to fetch distinct values. Please note you can combineorder_by and distinct

context = MyModel.objects.all().distinct('blog')
context = MyModel.objects.all().order_by('pub_date').distinct('blog')

 

.values()

Returns a QuerySet that returns dictionaries, rather than model instances, when used as an iterable.

context = MyModel.objects.all().distinct('blog').values()

 

Using Slugify with Django blog to create slug or url

In this article we will have a look at how to use Django utility to create slug field automatically and most importantly, you can create slugs in languages other than English too.

For creating blog application, please refer to post how to create Blog app using Django.

Once you create blog application, you admin screen will look something like below.

Here if you see carefully, slug is user input field, now we want to make it auto created field by making some changes into models.py

from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify                                # add this

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True,editable=False)  # Note the changes here, editable is false.
    author_local = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts',default="admin")
    updated_on = models.DateTimeField(auto_now= True)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    post_type = models.CharField(max_length=15,choices=POST_CHOICES,default=None,blank=True)
    category = models.CharField(max_length=50,default=None,blank=True)
    featured_image = models.ImageField(upload_to='img', blank=True, null=True)

    class Meta:
        ordering = ['-created_on']

    def save(self, *args, **kwargs):                                  # add this
        self.slug = slugify(self.title, allow_unicode=True)           # add this
        super().save(*args, **kwargs)                                 # add this

    def __str__(self):
        return self.title

Since you are making changes in models.py, you need to run following commands

 

$python3.6 manage.py makemigrations yourappname
$python3.6 manage.py migrate

 

Now access admin again, it will look like below and once you save the post, slug is automatically created.

Since we are using Unicode, it works for Devanagari script (Marathi and Hindi), I did not test for other languages but it would work for other languages too.

 

You might be wondering why content text field has options like WordPress editor in my screenshot. Please refer to post How to add Summernote WYSIWYG Editor in Django.

How to add Summernote WYSIWYG Editor in Django

After I created a blog application, biggest hurdle from using it is its admin editor. Anyone who has every used wordpress or any otehr blogging platform will not be OK to use simple text editor. I was searching for options to make the text field something like wordpress. I came across two options tinymce editor and Summernote.

I looked at install steps of tinymce and it looked complicated, I did not try and see if this works. When I looked at Summernote, it look simple and straghtforward and I decided to give it a try. Its very simple and it works perfectly fine.

Here are the steps for installtion

Step#1 Install Summernote package.

Install it just like any other python package. If you are using virtualenv, please make sure you install it in virtualenv

$pip install django-summernote
python -m pip install Pillow

Step#2 Changes in urls.py

Add this to main urls.py file

urlpatterns = [
..
..
    path('summernote/', include('django_summernote.urls')),
..
]
..
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  #add this for media

Step#3 Changes in settings.py

Add django_summernote in installed apps in settings.py file.

INSTALLED_APPS = [
    'blog.apps.BlogConfig', # add this statement
    'ifsccode.apps.IfsccodeConfig', # add this statement
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 'django.contrib.sites',
    'django.contrib.sitemaps',
    'django_summernote',          # This is added
]

 

Also add media folder settings at the end of settings.py

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

X_FRAME_OPTIONS = 'SAMEORIGIN'

Step#4 Changes in admin.py

Changes in admin.py

from django.contrib import admin
from django_summernote.admin import SummernoteModelAdmin

from .models import Post, Category, Comment, Tag


admin.site.register(Category)
admin.site.register(Comment)
admin.site.register(Tag)

...

class PostAdmin(SummernoteModelAdmin):    #added this
    summernote_fields = ('content',)      #added this

admin.site.register(Post, PostAdmin)

Please note that in above table, I have content field under Post

Step#5 Changes in Templates

Finally and most importantly, when you are displaying the field, mark it as safe.

<div id="postdetails">{{post.content|safe}}</div>

once this is done

Django admin CSS or static file not working [Solved]

You might have came across a situation where your application works perfectly fine on local machine but when deployed to production, everything works except admin section, technically it functions as expected but it does not have CSS. Why this happens ?

If you want to recreate this problem, just following in settings.py from True to False.

DEBUG = False
This happens because you application is not able to load css files for admin  functionality. To address this problem, please follow below mentioned steps.

Step#1 collectstatic

First you need to create a folder called static in your project root directory, then run below command
$python3.6 manage.py collectstatic.
This will move admin css files under static folder. You can see new folder created under static folder called admin. This folder will have admin view related css, js , fonts, img.
You might wonder where were these files before ? these were server from site-packages folder of Django. You dont need to dig details here, but if you want you can.

Step#2 Change server config.

When you are running, runserver, you are running development server and it does a lot of things for you, including serving of static files but in production, Django expects that the static files will be served by your serer.

This is not difficult at all, just have below changes done to your nginx server config.

server {
    server_name domainname.com www.domainname.com;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/domainname.sock;
    }

    location /static {                        # add this
       alias /var/www/domainname/static;      # add this
    }                                         # add this

}

if you are hosting django application using uwsgi and NGINX, this will work for you. I am not sure about gunicorn server. You can check post deploying django with uwsgi and nginx for deployment of your application to server.

First make sure you application is working on production server and then work on to make admin successfully.  Deploying Django to server has its own challenges, don’t make it more complicated by adding this change too. Attack problems one at a time.

Please let me know if you faced any issue while getting this working.

Create html or xml sitempa for Django app

If you are creating any content based website, it is utmost important to have a sitemap.   At first it looks like sitemap creation is complex using Django but if you understand the process its fairly simple. You can follow below steps to create simple sitemap.xml

Step#1 Config changes.

Add 'django.contrib.sitemaps', in INSTALLED_APPS section of settings.py
Also ensure following settings for TEMPLATES

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            BASE_DIR + '/templates/', # add this line
        ],
        'APP_DIRS': True,

Step#2 Create sitemap.py

Now cd to subapp directory and create file sitemaps.py as below

from django.contrib.sitemaps import Sitemap
from .models import Post
 
 
class PostSitemap(Sitemap):    
    changefreq = "monthly"
    priority = 0.9
 
    def items(self):
        return Post.objects.all()
 
    def lastmod(self, obj):
        return obj.created_on

changefreq can be hourly, monthly, never etc.

Most important point to be noted here. Whichever data model you are using, make sure it has function get_absolute_url()  defined.
for example

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    category = models.ForeignKey(Category, on_delete = models.CASCADE,verbose_name="Category",default=None,blank=True)
    updated_on = models.DateTimeField(auto_now= True)
    tags = models.ManyToManyField(Tag, related_name='rel_posts',default=None,blank=True)
    featured_image = models.ImageField(upload_to='img', blank=True, null=True)

    class Meta:
        ordering = ['-created_on']

    def get_absolute_url(self): #this is added for sitemap
        return '/'+self.slug
    def __str__(self):
        return self.title

Now make changes into blog/urls.py

from django.urls import path
from . import views
from django.contrib.sitemaps.views import sitemap
from .sitemaps import PostSitemap

sitemaps = {
    'posts': PostSitemap
}

app_name = 'blog'
urlpatterns = [
    path('', views.index, name='index'),  
    path('sitemap.xml', sitemap, {'sitemaps' : sitemaps } , name='sitemap'),  
]

Now if you try to access sitemap.xml, you can see it

http://127.0.0.1:8000/sitemap.xml/

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<urlset>
  <url>
    <loc>https://www.fintrekking.com/finance-is-everything</loc>
    <lastmod>2020-04-18</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.9</priority>
  </url>
</urlset>

Please notethat this siitemap is accessible from subapp. Either you need to make this subapp accessible on main url or this sitempa will be available at url something like below

http://127.0.0.1:8000/blog/sitemap.xml/

Please let me know if this works for you or if you faced any issue while making this work.

Deploy Django Application using NGINX, uWSGI

After developing couple of django application and testing them using inbuild development server (runserver), I was ready to deploy my Django application to VPS but littile did I know, deployment of django application is a big task itself.

I first started using official tutorial from Digital Ocean How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 16.04 but it turned out to be two complex. I spent almost a day but I ended up nowhere. I was searching for other way of deployment that’s when I came across uWSGI. You can find official documentation here. Setting up Django using uWSGI was not cakewalk either but I found it easy as compared to Gunicorn. In this effort, I spent almost two days but finally I got it working. I am documenting step by step actions as it might help someone and even future me 🙂

Step#1 Prepare environment

$sudo apt-get update
$sudo apt-get upgrade
$sudo python3.6 -m pip install virtualenv

Now let us create a django application on server. If you have already developed your application, you can deploy it to server using git as explained here or copy code using FileZilla or some other ways. For simplicity, I am creating an application.

$django-admin startproject yourapp
$cd yourapp
$python3.6 manage.py startapp blog
$virtualenv venvft
created virtual environment CPython3.6.4.final.0-64 in 453ms
creator CPython3Posix(dest=/var/www/yourapp/venvft, clear=False, global=False)
seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/home/user/.local/share/virtualenv/seed-app-data/v1.0.1)
activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

$source venvft/bin/activate
$pip install django 
$pip install psycopg2
deactivate

Please note the packages are installed inside virtual environment using pip install but outside it using command $sudo python3.6 -m pip install psycopg2. This command will not work inside virtual environment. Please don’t ask me why, I only know how. You can deactivate virtual environment at this stage.

Step#2 Django Application set up.

You already know what you need to do to set up django application. Changes to settings.py etc. For more details, you can refer to this post Building blog application using django.

Once basic setup is done, you need to run following commands

$ python3.6 manage.py makemigrations blog
$ python3.6 manage.py migrate

Before we test the application, please update ALLOWED_HOSTS in settings.py. Here ‘NNN.NN.NN.NNN’ stands for your server ip

ALLOWED_HOSTS = ['NNN.NN.NN.NNN','www.domain.com','domain.com','localhost','127.0.0.1','0.0.0.1']

Once done, let us test our application using our old development server. This is to ensure, our application is working fine. If you face any issue at this stage, it has nothing to do with server setup, tourbleshoot any Django related issue here. Only if you can run your application on development server, proceed to next step

python3.6 manage.py runserver

You can open new command prompt and test this using following

curl http://127.0.0.1:8000/

Step#3 Run using uWSGI server

Now lets run it using uwsgi using following command

sudo uwsgi --http 0.0.0.0:8000 --home /var/www/yourapp/venvft --chdir /var/www/yourapp/yourapp --wsgi-file /var/www/yourapp/yourapp/wsgi.py

Toubleshooting. There is possibility that you might get below error

ModuleNotFoundError: No module named 'yourapp'
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 28959, cores: 

In this case, you need to make few changes to yourapp/yourapp/uwsgi.py file

import os
import sys #added this

from django.core.wsgi import get_wsgi_application

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #added this
sys.path.append(BASE_DIR) #added this

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourapp.settings')

application = get_wsgi_application()

I have added comments about which line needs to be added. Now test again and it should work file.

Step# 4 uWSGI setup

Create a yourapp.ini file @ location /home/username/uwsgi/sites as below

[uwsgi]
home = /var/www/yourapp/venvft
chdir = /var/www/yourapp/yourapp
wsgi-file = /var/www/yourapp/yourapp/wsgi.py

#http = 0.0.0.0:8000

socket = /run/uwsgi/yourapp.sock
vacuum = true
chown-socket = username:www-data
chmod-socket = 666

Please change yourapp and username in this file as per your names

Now cd /etc/systemd/system/ and sudo nano uwsgi.service

[Unit]
#Description=uWSGI Emperor service
Description=uWSGI Emperor

[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown username:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /home/username/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

Here also. change the username to match yours.

After this is done cd /var/www/ and change ownership of project folder

sudo chown www-data:www-data -R yourapp

Step#5 NGINX setup

This is simplest of all. Simply use following code. If you are not aware, NGINX files are locared at location /etc/nginx/sites-available/

server {
    server_name yourdomain.com www.yourdomain.com;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/yourapp.sock;
        }
}

Now run following commands

sudo service nginx stop
sudo service uwsgi stop
sudo service nginx start
sudo service uwsgi start

Restart can also work but I prefer to stop and start.

Verification step

Now before you check your application on your browser cd /run/uwsgi and check file in this directory using ls -la

If there is no error you will see filename yourapp.sock. Now you are all set to access your application using its domain name.

Following links were very helpful for me. If you need any clarification or facing error, you can let me know or check below links