Django projenizi VPS üzerine deploy edin!

Django’nun en güzel özelliklerinden biri şüphesiz development servera sahip olması. Şahsen iş yerinde PHP kullanan biri olarak , geliştirme ortamınızı ayarlamak zorundasınız. Örneğin bir apache server ya da bir nginx server kurulumunu yapmak , gerekli PHP paketlerini yüklemek zorundasınız. Django’da ise , django kurulduktan sonra tek bir satır kod ile projeyi servis etme şansınız var. Ancak bu durum tabi ki geliştirme süreci için geçerli. Projenizi yayına almak istediğiniz zaman elimizi biraz taşın altına sokuyoruz. Başlamadan evvel sahip olmanız gereken şeyler ;

  1. VPS. Ben bunun için digitalocean ‘dan açtığım makineyi kullanıyorum. Fiyatı öğrenci arkadaşlar için uygundur.
  2. Domain Aslında domain sahibi olmasanız da olur , makinenizin ip adresini kullanarak da sonuçları görebilirsiniz. Ancak domain sahibiyseniz, DNS ayarlarınızın doğru olduğundan emin olun. Bunların dışında kurulum sırasında gunicorn, supervisor, nginx ve virtualenv araçlarını kullanacağım. Ayrıca veritabanı postgresql kullanacağım. Her birini arama motorlarında aratarak kullanımlarını öğrenebilirsiniz. Ben bizim için gerekli olan kısımları açıklayacağım. Başlamadan evvel aşağıdaki komutlarla depoları güncellemekte fayda var.
$ sudo apt-get update
$ sudo apt-get upgrade

Bu işlemden sonra postgresql’in kurulumunu yapalım.

$ sudo apt-get install postgresql postgresql-contrib

Kurulumdan sonra yeni bir kullanıcı ve veritabanı oluşturalım.  

$sudo su - postgres
postgres@MyDroplet:~$ createuser --interactive -P
Enter name of role to add:   django_db_user
Enter password for new role:
Enter it again:

Bu işlemden sonra size sorulan soruların tamamına hayır (n) diyebilirsiniz. Daha sonra ise yeni bir veritabanı oluşturalım.  

postgres@MyDroplet:~$ createdb --owner django_db_user hello_django
postgres@MyDroplet:~$ logout

Bu durumda veritabanımızın kullanıcısı django_db_user , veritabanımız ise hello_django olarak ayarlanıyor. Bu işlemden sonra virtualenv ortamını ayarlayalım. Virtualenv makine üzerine kuracağınız paketleri sanal bir ortama kurmak için kullanılır. Örnek vermek gerekirse elinizde 2 farklı Django ile yazılmış bir web projesi olduğunu ve bunların farklı sürümlerde çalıştığını hayal edin. Bu durumda iki adet virtualenv oluşturup her birine gereken sürümü yükleyebilir birbiriyle çakışmadan çalışmasını sağlayabilirsiniz.

$ sudo apt-get install python-virtualenv

Virtualenv kurduktan sonra bir tane oluşturmak için ;

$ sudo virtualenv /opt/myenv

Bu komut /opt/myenv dizinine bir virtualenv oluşturacaktır. Dediğimiz gibi makineye kuracağınız paketleri bu virtualenv ortamına kurmanız gerek. Dolayısıyla önce virtualenv ortamına geçiş yapmalısınız. Bunun için ;

$ source /opt/myenv/bin/activate

Komutunu kullanmalısınız. Bu ortamdan çıkış yapmak için ise ;

$ deactivate

komutu yeterli olacaktır. Virtualenv ortamına geçiş yaptıktan sonra,

$ pip install django

komutu ile django kurulumunu gerçekleştirebilirsiniz. Bu işlemden sonra virtualenv ortamından çıkıp. Nginx kurulumunu gerçekleştirebiliriz.

$ sudo apt-get install nginx

komutu bu konuda problemlerinizi tamamıyla çözecektir. Parçaları ayrı ayrı kurmamıza aldırmayın, birazdan bütün bu parçaları bir araya getireceğiz. Nginx web projenizi servis etmeniz için bir konteynır biz nginx ile django projesini konuşturmak için arada gunicorn dediğimiz yazılımı kullanacağız. Bu sebeple virtualenv ortamına geçip, gunicorn kurulumunu yapmalıyız.

$ pip install gunicorn

komutu ile gunicorn kurulumunu gerçekleştirelim. Aslında gunicorn ile tek başına django projesini servis edebiliriz. Ancak ortada bir django projesi yok! Öncelikle bir django projesi oluşturalım ve veritabanı bağlantısı için gerekli ayarları düzenleyelim. Tabi ki virtualenv ortamındayken - çünkü djangoyu bu virtualenv ortamında kurduk, bu ortam dışında django-admin.py’yi çalıştırmak isterseniz hata alırsınız-

$ cd /opt/myenv
$ django-admin.py startproject hello_django

komutları ile projemizi /opt/myenv dizini altına hello_django ismiyle oluşturalım. Postgresql kurulumunu yaptık ancak python’un postgresql ile anlaşabilmesi için psycopg2 isimli bir kütüphaneye ihtiyacı var. Bu kütüphaneyi kurmak için de;

$ pip install psycopg2

komutunu yazıyoruz. Şimdi projenin içinde (/opt/myenv/hello_django/hello_django/) settings.py dosyasını düzenleyip veritabanı bağlantısını gerçekleştirelim.

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'hello_django',
'USER': 'django_db_user',
'PASSWORD': '********',
'HOST': 'localhost',
'PORT': '',
}

Yukardaki ayarları yaptıktan sonra tablolarımızı ilklendirebiliriz.Bunlar django ile ilgili olduğu için pek üstünde durmaya gerek yok.

$ cd /opt/myenv/hello_django
$ python manage.py syncdb

Şu ana kadar birşeyi atlamadıysanız veya bir kurulumda hata almadıysanız tablolarınız daha önceden açtığımız veritabanında işlenmiş olmalı. Postgresql dökümantasyonlarına bakarak gerekli kontrolleri yapabilirsiniz. Söylediğim gibi aslında gunicorn ile projeyi tek başına servis edebilirsiniz. Gelin isterseniz gunicorn ile bir test yapalım.

$ cd /opt/myenv/hello_django
$ gunicorn hello_django.wsgi --bind 0.0.0.0:8000 --worker 3

komutlarıyla projenizi tıpkı $ python manage.py runserver der gibi servis edebilirsiniz. Şimdi makinenin ip’sini kullanarak(xxx.xxx.xx.xxx:8000 gibi) tarayıcıdan erişmeye çalışırsanız, karşınıza bir web sayfasının çıktığını görebilirsiniz. Static dosyalar görünmüyorsa , şimdilik kafanıza takmanıza gerek yok. Ancak fark ettiyseniz projeyi gunicorn ile servis ederken bind veya worker gibi belli parametreler kullandık. Bu parametreleri komut satırı üzerinden vermek yerine bir python dosyasına yazarak verebiliriz. Gelin bir konfigurasyon dosyası oluşturalım ve projeyi başlatmak istediğimizde hep bunu kullanalım.

$ cd /opt/myenv
$ sudo vi hello_django_gunicorn_cfg.py

 command = '/opt/myenv/bin/gunicorn' 
 pythonpath = '/opt/myenv/hello_django' 
 bind = '127.0.0.1:8001' 
 workers = 3 
 user = nobody

Burda user yerine nobody değeri geçildi, burada user parametresi geçmeyebilirsiniz. Ancak sağlıklı bir web uygulamasının unix kullanıcısı ayrı ve hakları kısıtlıdır. Bu güvenlik açısından önemli bir noktadır. Dolayısıyla unix üzerinde bir servis kullanıcısı açmanızı , projenin dosya haklarını bu kullanıcıya vermenizi, gunicorn config dosyasına ise bu kullanıcının adını yazmanızı tavsiye ederim. Ufak bir tüyo ile linux üzerinde şu komutla bir kullanıcı açabilirsiniz.

useradd --system --bash /bin/bash --home-dir /opt/myenv/hello_django hello_django_unix_user

Hatta daha sağlıklısı web uygulamalarının kullanıcılarını bir gruba atamak, örneğin webapps isminde bir gruba bu kullanıcıları dahil edebilir, gerekli unix yönetimini sağlayabilirsiniz. Ancak olayı şimdilik karıştırmaya gerek yok. Üstteki işlemi yaptıysanız hello_django_unix_user ismindeki kullanıcıyı config dosyasına yazabilirsiniz. Artık config dosyasını kullanarak projeyi başlatabilirsiniz. Virtualenv aktif haldeyken,

$ gunicorn -c /opt/myenv/hello_django_gunicorn_cfg.py hello_django.wsgi

komutu ile daha demin yaptığımız işlemi yapabiliriz. Bind ettiğimiz nokta farklı bir nokta olduğu için tarayıcıdan erişmeniz mümkün olmayabilir. Ancak bu ayarların yanına nginx i kattığımızda gunicorn kendi içinde 8001 portunda çalışan bir sunucu gibi olacak, nginx ise ön planda durup gelen istekleri gerekiyorsa gunicorna gönderecek. Statik olan dosyaları ise nginx ile servis edeceğiz. Nginx ayarlarını yapmadan önce statik dosyalar ile ilgili sorunlarımızı çözelim. Djangonun bu yönde güzel bir yanı var, kullandığınız bütün statik dosyaları tek bir noktaya toplayabiliyorsunuz. Bir django projesi oluşturduğunuzda admin paneli ile ilgili sayfaların dosyaları proje dosyaları içinde yer almaz, dolayısıyla projeyi taşıma esnasında sorunlar doğabilir. Bu nedenle django statik dosyaları tek bir noktaya taşımak için belirli yapılar geliştirmiş. Öncelikle statik dosyaların nerede toplanacağını djangoya söylememiz gerekiyor. Bunun için settings.py dosyasına aşağıdaki tanımlamayı yapmalıyız.

STATIC_ROOT = '/opt/myenv/hello_django_static'

Dikkat ettiyseniz virtualenv içerisinde ama proje dosyalarının dışında bir nokta seçtim. Bu iyi bir çözümdür. Virtualenv içerisine koyarsanız başka projelerle karışmaz, proje klasoru dışarısına koyarsanız hem güvenlidir, hemde versiyon kontrol sistemlerini ignore etmekle uğraştırmazsınız. Bu tanımlamayı yaptıktan sonra;

$ cd /opt/myenv/hello_django
$ python manage.py collectstatic

komutu ile statik dosyalarınızı toparlayabilirsiniz. Bu işlemi yaptıktan sonra artık nginx ayarlarını yapmaya hazırız.

$ sudo vi /etc/nginx/sites-available/hello_django

 server {   
   server_name domain.com;
   location /static/ {     
     alias /opt/myenv/hello_django_static;   
   }   
   location / {     
     proxy_pass http://127.0.0.1:8001
     proxy_set_header X-Forwarded-Host $server_name;     
     proxy_set_header X-Real-IP $remote_addr;
     add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';   
   }
 }

$ cd /etc/nginx/sites-enabled
$ sudo ln -s ../sites-available/hello_django
$ sudo service nginx restart

Bu işlemlerden sonra

$ cd /opt/myenv/
$ gunicorn -c hello_django_gunicorn_cfg.py hello_django.wsgi

Diyerek gunicornu aktif ediyoruz ve domainimize girmeye çalışıyoruz. Bu aşamadan sonra projenizi düzgün bir şekilde görüyor olmalısınız. Ancak bir sorun var, tüm bunları runserver gibi bir komut çalıştırmadan otomatik olarak yapmak istiyorduk. Araya bir sürü yazılım soktuk ama bir adım ileri gidemedik gibi duruyor. Yapmamız gereken son iş elle yaptığımız bu tetikleme işlemini supervisor diye isimlendirilen bir yazılıma teslim etmek. Bu yazılım sayesinde kendi yazdığınız scriptleri arka planda, otomatik olarak çalıştırabilirsiniz. Bu programı kurmak için virtualenv dışında,

$ sudo apt-get install supervisor

komutunu kullanabilirsiniz. Uzun bir konfigürasyondan sonra son olarak supervisor ayarlarını da yapalım. Supervisor ayar dosyalarını /etc/supervisor/conf.d dizininde saklıyor. Dolayısıyla yapmamız gereken ;

$ cd /etc/supervisor/conf.d
$ sudo vi hello_django.conf

  [program:hello_django] 
  command=/opt/myenv/bin/gunicorn -c /opt/myenv/hello_django_gunicorn_cfg.py hello_django.wsgi 
  autostart=true 
  autorestart=true 
  stderr_logfile=/var/log/long.err.log 
  stdout_logfile=/var/log/long.out.log 

Gördüğünüz gibi elle yazdığımız komudu command parametresinin değeri olarak yapıyoruz.Daha sonra supervisoru güncellemeliyiz.

$ supervisorctl reread
$ supervisorctl update

komutlarıyla çalıştırmaya başlayabiliriz. Restart atmak için ise;

$ sudo service supervisor restart

Dikkat etmeniz gereken bir nokta ise deploy aldığınız zaman statik dosyaları güncellemeyi unutmamak ve supervisor’ı da yenilemeniz atmanız olacaktır.