Blog

Crear un proyecto con Django en un servidor privado

Escrito por [email protected] o

Creamos una base de datos para la app (hello):

En este caso, elegimos postgreSQL

$ sudo aptitude install postgresql postgresql-contrib
$ sudo su - postgres
postgres@django:~$ createuser --interactive -P
Enter name of role to add: hello
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
postgres@django:~$

postgres@django:~$ createdb --owner hello_django hello
postgres@django:~$ logout

Creamos nuestro usuario

$ sudo groupadd --system hello_group # nome do grupo
$ sudo useradd --system --gid hello_group --shell /bin/bash --home /webapps/hello_django hello

Virtualenv

Instalamos el virtualenv si fuese necesario, sino simplemente creamos nuestro entorno virtual.

Para instalar virtualenv

$ sudo aptitude install python-virtualenv

Antes de crear nuestro entorno virtual, creamos el path (ruta) del proyecto

$ sudo mkdir -p /webapps/hello_django/
$ sudo chown hello /webapps/hello_django/

Identificamonos có usuario creado e lanzamos o comando de creación do entorno virtual, a opción '-p' usámola para poder indicar a versión de python

$ sudo su - hello
hello@django:~$ cd /webapps/hello_django/
hello@django:~$ virtualenv -p /usr/bin/python3.6 .
New python executable in hello_django/bin/python
Installing distribute..............done.
Installing pip.....................done.
hello@django:~$ source bin/activate
(hello_django)hello@django:~$

Una vez lcheegados a este punto, continuamos coa configuración do servidor, dandolle os permisos necesarios as carpetas

$ sudo chown -R hello:hello_group /webapps/hello_django
$ sudo chmod -R g+w /webapps/hello_django

Gunicorn

Para executar a nosa aplicación django en producción, utilizaremos Gunicorn. É necesario instalar gunicorn no entorno virtual do proxecto:

(hello_django)hello@django:~$ pip install gunicorn
Downloading/unpacking gunicorn
  Downloading gunicorn-0.17.4.tar.gz (372Kb): 372Kb downloaded
  Running setup.py egg_info for package gunicorn

Installing collected packages: gunicorn
  Running setup.py install for gunicorn

    Installing gunicorn_paster script to /webapps/hello_django/bin
    Installing gunicorn script to /webapps/hello_django/bin
    Installing gunicorn_django script to /webapps/hello_django/bin
Successfully installed gunicorn
Cleaning up...

Para arrancar unha aplicación Django con gunicorn:

(hello_django)hello@django:~$ gunicorn hello.wsgi:application --bind dominio.com:8001

Neste caso no porto 8001.

Agora vamos a crear un ficheiro 'bin/gunicorn_start' para utilizalo para iniciar a app

#!/bin/bash

NAME="hello_django_app"                                  # Name of the application
DJANGODIR=/webapps/hello_django/src/hello_django             # Django project directory
SOCKFILE=/webapps/hello_django/run/gunicorn.sock  # we will communicte using this unix socket
USER=hello_django                                        # the user to run as
GROUP=hello_group                                     # the group to run as
NUM_WORKERS=5                                     # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=hello_django.settings             # which settings file should Django use
DJANGO_WSGI_MODULE=hello_django.wsgi                     # WSGI module name
echo "Starting $NAME as `whoami`"

# Activate the virtual environment
cd $DJANGODIR
source /webapps/hello_django/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec /webapps/hello_django/bin/gunicorn \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --timeout=120 \
  --log-level=info \
  --log-file=- \
  ${DJANGO_WSGI_MODULE}:application

Este ficheiro debe ter permisos de execución:

$ sudo chmod u+x bin/gunicorn_start

Pódese probar que esta correcto, da seguinte maneira:

$ sudo su - hello
hello@django:~$ bin/gunicorn_start
Starting hello_app as hello
2013-06-09 14:21:45 [10724] [INFO] Starting gunicorn 18.0
2013-06-09 14:21:45 [10724] [DEBUG] Arbiter booted
2013-06-09 14:21:45 [10724] [INFO] Listening at: unix:/webapps/hello_django/run/gunicorn.sock (10724)
2013-06-09 14:21:45 [10724] [INFO] Using worker: sync
2013-06-09 14:21:45 [10735] [INFO] Booting worker with pid: 10735
2013-06-09 14:21:45 [10736] [INFO] Booting worker with pid: 10736
2013-06-09 14:21:45 [10737] [INFO] Booting worker with pid: 10737

^C (CONTROL-C to kill Gunicorn)

Formula para calcular os --workers (NUM_WORKERS): 2 * CPUs + 1.

Supervisor

$ sudo aptitude install supervisor

Unha vez instalado supervisor, debemos crear o ficheiro de configuración:


[program:hello]
command = /webapps/hello_django/bin/gunicorn_start ; Command to start app 
user = hello ; User to run as 
stdout_logfile = /webapps/hello_django/logs/gunicorn_supervisor.log ; Where to write log messages 
redirect_stderr = true ; Save stderr in the same log 
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 ; Set UTF-8 as default encoding

Crearémos un ficheiro para almacenar os mensaxes de log:


hello@django:~$ mkdir -p /webapps/hello_django/logs/
hello@django:~$ touch /webapps/hello_django/logs/gunicorn_supervisor.log

Logo é necesario gardar a configuración e engadir a app a supervisor

$ sudo supervisorctl reread 
hello: available 
$ sudo supervisorctl update 
hello: added process group

Algún comandos de supervisor interesantes:


$ sudo supervisorctl status 
hello hello RUNNING pid 18020, uptime 0:00:50 
$ sudo supervisorctl stop hello 
hello: stopped 
$ sudo supervisorctl start hello 
hello: started 
$ sudo supervisorctl restart hello 
hello: stopped 
hello: started

Nginx


$ sudo aptitude install nginx 
$ sudo service nginx start

Crearemos o ficheiro de configuración /etc/nginx/sites-available/hello da siguinte maneira:


upstream hello_django_app_server {

    fail_timeout=0 means we always retry an upstream even if it failed

    # to return a good HTTP response (in case the Unicorn master nukes a # single worker for timing out).
    server unix:/webapps/hello_django/run/gunicorn.sock fail_timeout=0;

}

server {

listen   80;
server_name hello_django.dominio.com;

client_max_body_size 4G;

access_log off; #/webapps/hello_django/logs/nginx-access.log;
error_log /webapps/hello_django/logs/nginx-error.log;

location /static/ {
    alias   /webapps/hello_django/src/hello/static/;
    expires 365d;
}

location /media/ {
    alias   /webapps/hello_django/src/media/;
    expires 365d;
}
location / {
    # an HTTP header important enough to have its own Wikipedia entry:
    #   http://en.wikipedia.org/wiki/X-Forwarded-For
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # enable this if and only if you use HTTPS, this helps Rack
    # set the proper protocol for doing redirects:
    #proxy_set_header X-Forwarded-Proto https;

    # pass the Host: header from the client right along so redirects
    # can be set properly within the Rack application
    proxy_set_header Host $http_host;

    # we don't want nginx trying to do something clever with
    # redirects, we set the Host: header above already.
    proxy_redirect off;

    # set "proxy_buffering off" *only* for Rainbows! when doing
    # Comet/long-poll stuff.  It's also safe to set if you're
    # using only serving fast clients with Unicorn + nginx.
    # Otherwise you _want_ nginx to buffer responses to slow
    # clients, really.
    # proxy_buffering off;

    # Try to serve static files from nginx, no point in making an
    # *application* server like Unicorn/Rainbows! serve static files.
    if (!-f $request_filename) {
        proxy_pass http://hello_django_app_server;
        break;
    }
}

# Error pages
error_page 500 502 503 504 /500.html;
location = /error.html {
    root /webapps/hello_django/src/hello_django/templates/;
}
# Compression

# Enable Gzip compressed.
gzip on;

# Enable compression both for HTTP/1.0 and HTTP/1.1.
gzip_http_version  1.1;

# Compression level (1-9).
# 5 is a perfect compromise between size and cpu usage, offering about
# 75% reduction for most ascii files (almost identical to level 9).
gzip_comp_level    5;

# Don't compress anything that's already small and unlikely to shrink much
# if at all (the default is 20 bytes, which is bad as that usually leads to
# larger files after gzipping).
gzip_min_length    256;

# Compress data even for clients that are connecting to us via proxies,
# identified by the "Via" header (required for CloudFront).
gzip_proxied       any;

# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client's Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
gzip_vary          on;

# Compress all output labeled with one of the following MIME-types.
gzip_types
  application/atom+xml
  application/javascript
  application/x-javascript
  application/json
  application/js
  application/rss+xml
  application/vnd.ms-fontobject
  application/x-font-ttf
  application/x-web-app-manifest+json
  application/xhtml+xml
  application/xml
  font/opentype
  image/svg+xml
  image/x-icon
  text/css
  text/plain
  text/javascript
  text/xml
  text/x-component;


}

Un enlace para activar o sitio:

$ sudo ln -s /etc/nginx/sites-available/hello /etc/nginx/sites-enabled/hello

Por último reiniciamos Nginx:

$ sudo service nginx restart 

 

Se todo saíu ben, deberíamos ter o sitio funcionando no noso servidor de producción