Crear un proyecto con Django en un servidor privado

Escrito por chucu el

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

En este caso, elegimos postgreSQL

$ sudo aptitude install postgresql postgresql-contrib
$ sudo su - postgres
[email protected]:~$ 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
[email protected]:~$

[email protected]:~$ createdb --owner hello_django hello
[email protected]:~$ 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


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
[email protected]:~$ cd /webapps/hello_django/
[email protected]:~$ virtualenv -p /usr/bin/python3.6 .
New python executable in hello_django/bin/python
Installing distribute..............done.
Installing pip.....................done.
[email protected]:~$ source bin/activate
(hello_django)[email protected]:~$

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


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

(hello_django)[email protected]:~$ pip install gunicorn
Downloading/unpacking gunicorn
  Downloading gunicorn-0.17.4.tar.gz (372Kb): 372Kb downloaded
  Running egg_info for package gunicorn

Installing collected packages: gunicorn
  Running 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)[email protected]:~$ gunicorn hello.wsgi:application --bind

Neste caso no porto 8001.

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


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
source /webapps/hello_django/bin/activate

# Create the run directory if it doesn't exist
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=- \

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
[email protected]:~$ 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.


$ sudo aptitude install supervisor

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

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:

[email protected]:~$ mkdir -p /webapps/hello_django/logs/
[email protected]:~$ 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


$ 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;

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:
    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;

# 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.


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