Deploy Django in Sub-Directory behind uWSGI and NGINX on CentOS 7

It took me awhile to deploy Django in sub-directory. Actually, I move it from sub-domain to sub-directory. I hope this post will save you some hours searching the Internet.

Prerequisite or situation

You are running Django in sub-domain, another domain and you want to move it to a sub-directory. You’re properly having issue with urlpatterns which may lead to code revise. However you still want to keep your code same.

You may also want to check out how to Setup Django behind uWSGI and NGINX on CentOS 7. FYI I am currently using Linode and DigitalOcean to host my sites.

Deploy Django in sub-directory

If you are running Django, along with WordPress, on a VPS like me, you only need to update NginX & uWSGI configuration files.

uWSGI ini

NginX configuration file

Wrap it up

Here you go demo: https://www.vndeveloper.com/django-demo/

That’s it. There are only few things from configuration files. You may also want to check out Setup Django behind uWSGI and NGINX on CentOS 7 to understand how to configure at server side.

References:
[1] https://uwsgi-docs.readthedocs.io/en/latest/Changelog-2.0.11.html#fixpathinfo-routing-action

Web Server (VPS) Optimization Checklist for WordPress

I have been using VPS as web server since 2005 to host my sites. Before that, I switched among shared web hosting for many reasons. One of them is cost efficiency because I have more than one websites (using WordPress). I also want to try some thing else like Django, Flask which I cannot do with share web hosting.

If you are about to start a WordPress blog for the first time, you may want to start with shared web hosting. Below are list of shared web hosting suggested by WordPress.org

Spin up a VPS web server

I am currently using both Linode and DigitalOcean for my sites. They are all good and I want to experience with both so I keep using both till now. You can pickup one of them or one at your own choice. There are long list of VPS provider so please do some researches.

I wrote a tutorial on how to setup LEMP stack on CentOS 7. So please go ahead to check it out for basic web server setup.

VPS optimization for WordPress

Below is checklist or to-do list that we need to work on our VPS

  • Configure Nginx with HTTP 2 support
  • PHP extensions, Zend Opcache
  • Nginx GZIP Compression configuration
  • Install and configure Nginx module Brotli Compression
  • Install and configure Nginx module  Google PageSpeed
  • Use W3-Total-Cache: this is actually not server side directly related. However you cannot or hard to use W3-Total-Cache without full control web server.
  • Install and configure Memcached so you won’t get MySQL crash sometime or “Error establishing a database connection”. This one can also speed up your WordPress site since required data is already in memory & smaller PHP script needs to be executed meaning faster web site.
  • If your site already has some content with images, you may want to optimize them using optipng, jpegoptim, pngquant, etc.

web server test result

Final thought

Fast web site needs not only strong web server but also well configured. You really don’t want to pay for a super strong VPS and still see loading time of your site more than 3 seconds. All VPSs’ I used so far is $5/month (1vCPU, 1GB of RAM, 25GB SSD).

Setup Django behind uWSGI and NGINX on CentOS 7

Setting up a web server for Django could be challenging and headache. Let’s try to make it simple: Django behind uWSGI and NGINX on CentOS 7 from scratch. At the end, our complete stack of components will look like this:

the web client <-> the web server <-> the socket <-> uwsgi <-> Django

1. Install Dependencies

Assuming that you are working on a smallest VPS like mine (1GB of RAM, 1 vCPU, 25GB SSD). I am currently use Linode and DigitalOcean.

1.1. NGINX

yum install epel-release -y
yum install nginx -y

1.2. Python 3 & PIP

yum install python34-devel gcc -y
curl -O https://bootstrap.pypa.io/get-pip.py
/usr/bin/python3.4 get-pip.py

1.3. Create VirtualEnv with Python3

pip install virtualenv
mkdir -p /var/www && cd /var/www
python3.7 -m venv p3venv

If you are up-to-dated person, you can install 3.6.2 (latest python version as of now – Aug 28, 2017) follow this instruction https://janikarhunen.fi/how-to-install-python-3-6-1-on-centos-7.html

1.4. Install uWSGI & Django

# Activate virtual environment
source p3venv/bin/activate
pip install uwsgi
pip install django

2. Configurations

2.1. Basic NGINX config

For simplest & testing purposes, let’s create NGINX server block by issuing “vi /etc/nginx/conf.d/django.conf”. Any *.conf file inside this folder will be loaded as per instructed by main & default NGINX configuration (/etc/nginx/nginx.conf).

Save NGINX config and start NGINX service: systemctl start nginx

As of now, we have NGINX serves static files and by pass others to Django Server which will be configured shortly. It means you will get 502 bad gateway when accessing the site but this is totally fine.

2.2. Create Django project

# Make sure we are in right place
cd /var/www/example
django-admin.py startproject djangodemo
# Also allow domain or IP in Django settings (/var/www/example/djangodemo/djangodemo/settings.py)

Test if they look good by starting Django Development and uWSGI server. You will get “It worked! Congratulations on your first Django-powered page.”

python manage.py runserver 0.0.0.0:8000 ("ctrl + c" to terminate)
uwsgi --http :8000 --module djangodemo.wsgi ("ctrl + c" to terminate)

Alright, let’s configure uWSGI as service so we don’t have to keep terminal open.

2.3. Configure uWSGI as service

Save djangodemo_uwsgi.ini file and create symlink from the default config directory to your config file

ln -s /var/www/example/djangodemo/djangodemo_uwsgi.ini /etc/uwsgi/vassals/

Quick test if the configuration is good by start uWSGI server and navigate to the site. You should get “It worked! Congratulations on your first Django-powered page.”
/var/www/p3venv/bin/uwsgi --emperor /etc/uwsgi/vassals
Ctrl + C to terminate uWSGI server and let’s make it runs as a service

Start uWSGI and NGINX services and you should be able to access to your Django app without having to hold terminal open.

systemctl start uwsgi
systemctl restart nginx

Final thought

Congratulations. You’ve completed setting up NGINX, uWSGI to serve Django application. I know this is not so easy, especially when you are new to Django and uWSGI like me. It took me almost 2 weeks to search and try things out before writing this article.

I am still stuck at djangodemo_uwsgi.ini with chmod-socket = 666. Whenever I change it to chmod-socket = 664, I get 502 bad gateway. If someone knows the cause and how to fix it, please let me know.

Any input or comment are more than welcomed and appreciated. So why not leave a comment now, huh?

Image credit: http://technerd.tistory.com/55

References:
– https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
– https://www.youtube.com/watch?v=DzXCHAuHf0I
http://ask.xmodulo.com/install-python3-centos.html
– https://stackoverflow.com/questions/41588925/pip-install-django-on-python3-6
– https://www.nginx.com/resources/admin-guide/gateway-uwsgi-django/

Building a secured Java web server using Spark framework and Nginx

Spark framework (www.sparkjava.com) is a small Java framework used to build a REST server quickly. You can build a Java web server with only a few lines of code. But adding SSL to your server needs more effort.

Java used its own format for the keystore file which contains keys. First of all, you need to generate your private key. Java key tool will store it in a keystore file .jks. The following command creates a key has 2048 bit length for localhost valid in one year:
keytool -genkey -alias localhost -keyalg RSA -keystore KeyStore.jks -validity 365 -keysize 2048

Now you have your private key in the keystore file. Here is a code snippet to build a web server using Spark framework:

[java]

import spark.Request;
import spark.Response;

import static spark.Spark.*;

public class Server {
private final int port = 12345;

public Server() {
port(port);
secure("KeyStore.jks", "password", null, null);

get("/", (request, response) -> {
return "Hello World";
});
}
}

[/java]

This code load the keystore you’ve recently created to support SSL. Try to access your server with the URL: https://localhost:12345/, you’ll get the text “Hello World”.

Your web server supports SSL, but it’s quite dangerous when you exposing it directly to the world. Enhancing security of your web server by adding a proxy in front of it. Requests will go to your proxy first, then your proxy forward it to your server.

I use Nginx (www.nginx.com) for this purpose. This is a famous web server that solved the C10K problem (https://en.wikipedia.org/wiki/C10k_problem). After installing it, change its configuration file (conf/nginx.conf) to allow forwarding requests to your server:

[sourcecode language=”plain”] # HTTPS server
server {
listen 443 ssl;
server_name localhost;

ssl_certificate "localhost.crt";
ssl_certificate_key "localhost.key";

server_tokens off;

#ssl_session_cache shared:SSL:1m;
#ssl_session_timeout 5m;

#ssl_ciphers HIGH:!aNULL:!MD5;
#ssl_prefer_server_ciphers on;

location / {
proxy_pass https://localhost:12345;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
[/sourcecode]

Please replace ‘localhost’ at ‘server_name’ field by your real domain. This configuration file guides Nginx server to listen at port 443 (SSL port) and forward requests to your web server at port 12345. Please note that you’ll need a private key and a certificate for your Nginx server. They’re different from the keystore of your web server. The OpenSSL tool (www.openssl.org) will help you to generate them easily, or you may want to contact to a CA to get an authorized certificate.

Try to open the URL https://. It’ll return ‘Hello World’. You’ve built a secured java web server successfully!

Self-signed certificate for local HTTPS connection

When setting up an HTTPS server for development purpose, you probably don’t want to buy a certificate. However you still need to run with HTTPS locally to develop/test if your web application works under HTTPS connections. You can create a self-signed certificate for free using OpenSSL.

Generate a private key

This command is to genetate a 4096-bit private key using SHA512 algorithm:

openssl genrsa -out localhost.key 4096 -sha512

-out <filepath> : path of the output file that will contain private key
-sha[number] : the algorithm applies for private key, it can be sha1, sha256, sha512; default value is sha1 if this parameter is missing. sha1 is not recommended because browsers like Chrome will treat it as unsecured.

Generate a Certificate Signing Request (CSR)

A CSR file will contain information about your organization and needs to use the private key. You can include organization details in only one command line, otherwise it will ask you to input manually for each field. The following command generates a CSR file using SHA512 algorithm:

openssl req -new -key localhost.key -out localhost.csr -sha512 -subj “/C=US/ST=State/L=City/O=Your Organization/CN=localhost”

out <filepath> : path of the output fle that will contain a Certificate Signing Request
subj : subject details included in the CSR
/C : two letters of country code
/ST: full name of state
/L: full name of city
/O: full name of your organization
/CN: usually a domain name which you want to install certificate on

Generate the certificate based on the CSR and sign it using the private key

The following commands create a X509 certificate which is valid within 365 days from the creation date and uses SHA-512 algorithm:

openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt -fingerprint -sha512

-days <number> : number of days from the creation date that the certificate is still vallid
– in <filepath> : path of the CSR file
– out <filepath> : path of the output certificate file
– fingerprint : to print information of fingerprint to check the algorithm used in this certificate

Now you can install both your private key file and your certificate file to your server.

Notes

OpenSSL needs its configuration file. If you’re using Windows build from GnuWin32, you can set the environment variable ‘OPENSSL_CONF’ to  the OpenSSL config file using the following command:

set OPENSSL_CONF=C:\Program Files (x86)\GnuWin32\share\openssl.cnf

The certificate is not signed by a Trusted CA. So it will be treated as not secured by browsers and rejected by Postman. You can import it as a trusted certificate into the certicate store on your machine.

Compile Nginx with Pagespeed Module From Source

Compile Nginx with Pagespeed Module From Source is not hard as you may think. Below NGINX setup is fit for NGINX + FastCGI Cache. It means you don’t have to use WP Super Cache or W3 Total Cache or any cache plugin.

Basic Setup

  • Keep CentOS 7 up to date
  • Disable Root access
  • Firewall
  • Timezone configuration

Install Dependencies

yum install wget curl unzip gcc gcc-c++ pcre-devel zlib-devel make openssl-devel

You may also check out How to upgrade OpenSSL on Centos 7 or RHEL 7.

Compile NGINX From Source

First download ngx_pagespeed

Check the release notes for the latest version

NPS_VERSION= cd wget https://github.com/pagespeed/ngx_pagespeed/archive/v${NPS_VERSION}-beta.zip
unzip v${NPS_VERSION}-beta.zip
cd ngx_pagespeed-${NPS_VERSION}-beta/
psol_url=https://dl.google.com/dl/page-speed/psol/${NPS_VERSION}.tar.gz
[ -e scripts/format_binary_url.sh ] && psol_url=$(scripts/format_binary_url.sh PSOL_BINARY_URL)
wget ${psol_url}
tar -xzvf $(basename ${psol_url}) # extracts to psol/

Download and build nginx with support for pagespeed

Check nginx’s site for the latest version

NGINX_VERSION= cd wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar -xvzf nginx-${NGINX_VERSION}.tar.gz
cd nginx-${NGINX_VERSION}/
./configure –add-module=$HOME/ngx_pagespeed-${NPS_VERSION}-beta ${PS_NGX_EXTRA_FLAGS}
make sudo
make install

Above configuration just compile NGINX with Pagespeed. I’d recommend below configuration so you can test more things. Then followed by ‘make’ and ‘sudo make install’.

./configure \
–with-pcre \
–with-http_ssl_module \
–with-http_v2_module \
–with-threads \
–with-http_image_filter_module \
–with-http_gzip_static_module \
–add-module=$HOME/ngx_pagespeed-${NPS_VERSION}-beta \
–add-module=$HOME/ngx_cache_purge-master \
–add-module=$HOME/headers-more-nginx-module-master

Note that I also have ngx_cache_purge & headers-more-nginx-module.

Configure NGINX Service

Now we will create Init Script and save it at “/etc/init.d/nginx”. Please pay attention to 3 highlighted lines (binary, configuration and pidfile) and update it properly same as your configurations. This is a bit tricky for one who is new to NGINX. Feel free to leave a comment or create a topic if you need help.

Finally, start NGINX

chmod +x /etc/init.d/nginx
systemctl daemon-reload
systemctl start nginx
systemctl status nginx

Nginx Status

By default, NGINX will run with 1 processor but you can configure number of processor in nginx.conf.

You will see this default index page when accessing http://IP/. I am using Chrome Extension named Wappalyzer to view site’s information.

Nginx Info

Summary

We compile NGINX with default modules like pre-built as well as Pagespeed module. It also doesn’t have issue “Failed to read PID from file /run/nginx.pid: Invalid argument” mentioned in reference #6. Please leave a comment  or feedback right below.

References
1. https://modpagespeed.com/doc/build_ngx_pagespeed_from_source
2. https://modpagespeed.com/doc/configuration
3. https://www.nginx.com/resources/wiki/start/topics/examples/redhatnginxinit/
4. https://www.nginx.com/resources/wiki/start/topics/tutorials/gettingstarted/
5. https://github.com/pagespeed/ngx_pagespeed
6. https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/1581864