Eseguire un’applicazione Django su ubuntu server con nginx, gunicorn, upstart e mysql (DUNG stack)

Gunicorn

Oggi torno a scrivere sul blog per raccontare come eseguire il deploy di un’applicazione Django su ubuntu server con Nginx come web server, Gunicorn come application server WSGI e MySQL come DBMS.

Inizialmente per ospitare un’applicazione scritta con il framework Django utilizzavo un classico stack in stile LAMPP (Linux + Apache + mod_wsgi). Successivamente per cercare di limitare l’utilizzo di ram ho scoperto (grazie al blog degli ingegneri di instagram) lo stack DUNG che rappresenta la configurazione con nginx + gunicorn + ubuntu.

Non appena si iniziano le configurazioni si comprendono la semplicità e la velocità di messa a punto del nuovo stack. Nginx usa file di configurazione scritti con una sintassi simile ad un linguaggio di programmazione, molto più semplici da comprendere e da scrivere per chi ha poca dimestichezza con queste cose.

Per prima cosa installiamo nell’ordine mysql e nginx, successivamente installiamo django.

Fatto ciò, tramite easy_install possiamo installare Gunicorn:

sudo easy_install gunicorn

A questo punto dobbiamo configurare nginx come proxy server per le richieste: tutto ciò che riguarda i file statici (immagini, css, js, ecc…) verrà servito direttamente da nginx mentre le richieste inerenti il codice python dovranno essere girate al server WSGI (gunicorn nel nostro caso) che le eseguirà e restituirà la pagina risultante.

Come per apache i file di configurazione dei vari siti sono in /etc/nginx/sites-available (invece di /etc/apache/sites-available), per cui creiamo il file di configurazione per la nostra applicazione django in questo modo:

upstream project {
        server 127.0.0.1:8200 fail_timeout=0;
        server 127.0.0.1:8201 fail_timeout=0;
}

server {
        listen 80;
        server_name mydomain.com www.mydomain.com;
        access_log /var/log/nginx/mydomain_access.log;
        error_log /var/log/nginx/mydomain_error.log;

        root /srv/django_srv/mydomain/app;

        location / {
                proxy_set_header Host $host;
                if (!-f $request_filename){
                        proxy_pass http://project;
                        break;
                }

        }
        location /upload  {
                alias /srv/django_srv/mydomain/uploads;
                }
        location /static  {
                alias /srv/django_srv/mydomain/app/_statics;
        }
        location /admin/media {
                alias /opt/Django-1.3.1/django/contrib/admin/media;
        }
}

Come potete vedere nel blocco di configurazione upstream project a questo punto dobbiamo configurare gunicorn in modo da farlo rispondere sulla porta 8200 e 8201. In questo modo quando caricheremo aggiornamenti del nostro progetto e dovremmo riavviare gunicorn, il sito non sarà mai irraggiungibile, inoltre se il processo gunicorn dovesse crollare per qualche motivo ce ne sarà sempre un altro disponibile. Gli alias che vedete sono per i file uploadati dagli utenti tramite l’applicazione, i file statici del sito e i file statici per il backend amministrativo (per questi ultimi dovete dare il path alla cartella di installazione di Django). Dopo aver salvato questo file create un link simbolico nella cartella effettiva dei siti di nginx:

ln -s /etc/nginx/sites-available/mydomain.com /etc/nginx/sites-enabled/mydomain.com

Per avviare gunicorn, essendo su ubuntu, utilizziamo upstart il nuovo sistema per avviare tasks e servizi all’avvio del sistema. Creiamo il file /etc/init/gunicorn_8200.conf e copiamo le seguenti istruzioni:

description "Gunicorn Django on 127.0.0.1:8200"
start on runlevel [2345]
stop on runlevel [06]
respawn
respawn limit 10 5
exec /usr/local/bin/gunicorn_django --bind=127.0.0.1:8200 --workers=2 --access-logfile=/var/log/gunicorn/8200_access.log --error-logfile=/var/log/gunicorn/8200_error.log --daemon /srv/django_srv/mydomain/app/settings.py

Con queste istruzioni diciamo al processo gunicorn di ripartire in caso di crash (respawn) di rispondere all’indirizzo 127.0.0.1 sulla porta 8200 (–bind) di partire come demone (–daemon) e gli diamo i percorsi dei file di log e del file di settings della nostra applicazione.

A questo punto riavviamo il server per verificare che anche upstart funzioni:

shutdown -r now

Il gioco è fatto e la nostra applicazione è pronta per essere utilizzata. I file del progetto django (in base a questa configurazione) devono risiedere in /srv/django_srv/mydomain/app, mentre i file di upload sono in /srv/django_srv/mydomain/uploads per fare in modo che non siano all’interno dell’applicazione e che siano facilmente backuppabili ;)

Spero di essere stato esaustivo, di sicuro con questa configurazione vi potrete accorgere del notevole risparmio di ram rispetto ad un classico stack che utilizza apache come webserver.