Python ile web tabanlı uygulamalar geliştirmek her ne kadar bir çok yönden avantajlı olasa da kendi içerisinde bazı dezavantajlarıda mevcut. Bu dezavantajlardan biriyse, geliştirilen uygulamanın yayına alınmasının PHP gibi betik dillerine nazaran daha fazla efor sarfettirmesidir.
Bu, Python’ın çok yönlü bir dil olmasından kaynaklı bir durum. Çünkü Python ile sadece web tabanlı uygulamalar geliştirilmiyor, bir çok şey yapılabiliyor. Dolayısıyla uygulamayı yayınlamadan önce sunucumuzu Python için özel olarak yapılandırmamız gerekiyor yada Python destekli paylaşımlı bir hosting edinmemiz gerekiyor. Pratikte Python ile geliştirilmiş bir web uygulamasını yayına almak (deploy işlemi) için 3 yol mevcut.
- Python destekli, paylaşımlı bir hosting üzerinde yayınlamak. (İlgili Blog Yazısı İçin Tıklayın)
- Dockerize edip bir sunucu üzerinde yayınlamak.
- Sunucuyu, web uygulamamız için özel olarak yapılandırıp yayınlamak.
İlk yöntem en kolay yöntem olsada, uygulamanızın eğer bazı bağımlılıkları varsa (redis, celery vs gibi) ve hosting firmanız bunu sağlamıyorsa işinize yaramayacaktır.
Dockerize yöntemi en kolay ve stabil yöntem olsada Docker ile uğraşmak istemediğiniz yada yetersiz kaynağa sahip sunucularda yine işinize yaramayacaktır.
Bu yüzden biz, bu yazıda 3. yöntemi inceleyeceğiz ve Ubuntu bir sunucu üzerinde nasıl yayına alacağımızı göreceğiz. Sunucuyu bir kez yapılandırdıktan sonra yeni uygulamaları yayınlamak oldukça kolay hale gelecektir.
Diğer 2 yöntem içinse fırsat buldukça yazılar hazırlayacağım. Haydi başlayalım.
Gereksinimler
Bir web uygulaması yayınlamak için çeşitli servislere ihtiyaç var ve bu servislerin yönetimi çeşitli uygulamalar yardımı ile yapılabilir. Bu servisler, açıklamaları ve bu servisleri kontrol edecek uygulamalar aşağıdaki tablodaki listelenmiştir.
Servis | Açıklama | Uygulama |
---|---|---|
Web Uygulaması | Yayına alınacak Flask uygulaması | Confidant |
WSGI Servisi | Uygulamamızı yayınlayacak servis | Gunicorn |
Process Control Servisi | Uygulamamızı yönetecek ve loglayacak servis | Supervisor |
HTTP Server | Proxy işlemlerini yönetecek ve statik dosyaları yayınlayacak servis | Nginx |
Firewall | Sunucu güvenlik duvarı ve port kontrol işlemlerini yapacak servis (isteğe bağlı) | UFW |
Sanal (İzole) Ortam | Proje paketlerinin, sistem ve diğer projelerin paketleri ile çakışmamasını sağlayacak servis (isteğe bağlı) | Virtualenv |
Versiyon Kontrol Sistemi | Projenin sürüm kontrol işlemlerini yönetecek servis (isteğe bağlı) | Git |
Bu yazıda örnek olması için bir günlük olan Confidant uygulamasını kullanacağım. İsterseniz tabloda önerdiğim uygulamaları, kendi taleplerinize göre alternatif uygulamalar ile değiştirebilirsiniz.
Kurulum
İlk işlemler
Kuruluma başlamadan önce bir Ubuntu sunucu kiralamamız gerekmekte. Sunucuyu kiraladıktan sonra bize verilen erişim bilgileri ile sunucumuza erişiyoruz ve sunucumuzu güncelliyoruz.
~$ sudo apt-get update && apt-get upgrade
Güncelleme işlemi biraz uzun sürebilir. Tamamlandıktan sonra sunucuya gerekli uygulamaları kurmaya başlayabiliriz.
Not: Devam etmeden önce, root olarak sunucuda işlem yapmak oldukça tehlikeli olacağından yeni bir kullanıcı hesabı oluşturulması önerilir. Oluşturulan kullanıcı ile sisteme tekrar giriş yaparak işlemlere devam edebilirsiniz.
Şimdi sunucumuza Python, Git, PIP, Virtualenv gibi çeşitli programları kurmamız gerekiyor.
~$ cd ~
~$ sudo apt install python3 python3-pip git
~$ pip3 install virtualenv
İlk satırda ana dizinde olmama ihtimaline karşı kullanıcının ana dizinine geçiyoruz. İkinci adımda Python3, PIP ve Git kurulumlarını yapıyoruz. Son adımda ise projemiz için kullanılan python paketlerinin izole olması için virtualenv kurulumunu gerçekleştiriyoruz.
Uygulama Kurulumu
Artık Flask uygulamamızı kurabiliriz. Kullanıcının ana dizininde iken git ile projeyi klonluyoruz ve uygulama dizinine geçiyoruz. Eğer isterseniz sunucunuza FTP kurulumu yaparak, FTP kullanarak dosyalarınızı yükleyebilirsiniz.
~$ git clone https://github.com/emregeldegul/confidant && cd confidant
Daha sonra uygulamamızı sistemden izole bir şekilde çalıştırabilmek için virtualenv ile sanal ortam kurulumu yapıyorum ve sanal ortamı aktif hale getiriyorum.
~$ python3 -m virtualenv venv && source venv/bin/active
Bu komut sonrası eğer bir terslik olmadıysa sanal ortam aktif olacaktır. Yani bu projeye yükleyeceğiniz bütün paketler bu proje özelinde çalışacaktır. Eğer sanal ortam aktifse terminal aşağıdaki görünüme kavuşacaktır.
(venv) ~$
Şimdi, uygulamamız için gerekli bütün paketleri requirements.txt
dosyasından yükleyebilirsiniz.
(venv) ~$ pip install -r requirements.txt
WSGI servisinin (gunicorn
) requirements.txt
dosyası içerisinde tanımlandığına dikkat edin. Böylece WSGI servisini de kurmuş olduk.
Uygulama migration dosyalarıda içerdiğinden migration işleminide yapıyoruz (sizin uygulamanızda yoksa, geçebilirsiniz).
(venv) ~$ flask db upgrade
Güvenlik Duvarı ve Port Yönetimi
Uygulamamız henüz çalışır vaziyette değil. Öncelikle güvenlik duvarı kurulumunu yapacağız, yapmak istemiyorsanız bu adımı geçebilirsiniz.
Güvenlik duvarı olarak UFW kullanacağız. Oldukça basit olan bu uygulamayı kurmak ve ilk ayarları yapmak için sırasıyla aşağıdaki komutları verebilirsiniz.
~$ sudo apt install ufw
~$ sudo ufw default allow outgoing
~$ sudo ufw default deny incoming
~$ sudo ufw allow ssh
~$ sudo ufw allow 5000
~$ sudo ufw enabled
- Satır: UFW programını kurduk.
- Satır: Varsayılan olarak sunucudan dışarı çıkan bütün isteklere onay verdik.
- Satır: Varsayılan olarak sunucuya dışarıdan gelen bütün istekleri reddettik (portları kapattık).
- Satır: SSH servisine dışarıdan erişim izni verdik (varsayılan 22 numaralı port).
- Satır: 5000 numaralı porta dışarıdan erişim izni verdik.
- Satır: Güvenlik duvarını aktif hale getirdik.
Not 1: Güvenlik duvarını aktif hale getirmeden önce SSH erişimine izin vermeniz gerekiyor. Aksi durumda sunucu erişiminizi kaybedersiniz.
Not 2: 5000 numaralı port, uygulamamızı test ederken kullanacağımız porttur. Daha sonra kapatacağız.
İlk Kontrol Noktası
Eğer bütün işlemler tamamsa uygulamanın doğru çalışıp çalışmadığını test etme vakti geldi demektir. Uygulama dizinindeyken (ve sanal ortam aktifken) aşağıdaki komutu çalıştırıyoruz.
(venv) ~$ flask run --host=0.0.0.0 --port=5000
Her şey tamamsa tarayıcıdan http://sunucu_ip_adresi:5000
adresine gittiğimizde uygulama düzgün bir şekilde bizi karşılayacaktır. Aksi durumda adımlardan birinde hata yapmışız demektir. Şimdi ilk kontrolü sonlandırıp (CTRL + C
komutu ile sonlandırabilirsiniz) Supervisor ile uygulamayı kontrol etmek için gerekli ayarlamaları yapıyoruz. Ama önce 5000 numaralı portu erişime kapatalım.
~$ sudo ufw delete allow 5000
Supervisor Kurulumu
Supervisor, uygulamalarımızı yönetecek, loglarını tutacak ve daima çalışmasını sağlayacak basit ve etkili bir program. Ayrıca web arayüz desteğide sunuyor ki bu oldukça hoşuma gidiyor.

Kurulum için aşağıdaki komutu sisteme veriyoruz.
~§ sudo apt-get install supervisor
Hepsi bu kadar, supervisor sisteme kuruldu. Supervisor konusunda daha fazla detay isterseniz aşağıdaki yazıyı size öneririm.
Ali Orhun Akkirman: Supervisor Süreç Yöneticisi
Supervisor, yöneteceği her uygulama için /etc/supervisor/conf.d/
dizinin içerisinde .conf
uzantılı bir yapılandırma dosyası oluşturmamızı istiyor. Dolayısıyla burada tanımlayacağımız her uygulama, supervisor tarafından yönetilebilir olacaktır. Hemen nano ile ilk yapılandırma dosyamızı oluşturuyoruz.
~$ sudo nano /etc/supervisor/conf.d/confidant.conf
Uygulama ismi ile yapılandırma dosyamı oluşturdum, şimdi içeriğini hazırlayabilirim.
[program:confidant]
directory=/home/<USER_PATH>/confidant
command=/home/<USER_PATH>/confidant/venv/bin/gunicorn -w 3 run:app -b 0.0.0.0:13001
user=<USER>
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stderr_logfile=/home/<USER_PATH>/logs/confidant/confidant.err.log
stdout_logfile=/home/<USER_PATH>/logs/confidant/confidant.out.log
Aslında yeterince açıklayıcı olduğunu düşünüyorum. Ancak yinede kabaca belirtmem gerekirse
1. satırda program ismini belirtiyoruz. Bu ismin benzersiz olmasına dikkat edin, uygulamamızı bu isimle yöneteceğiz.
2. satır uygulamamızın çalışma dizinini işaret eder.
3. satır uygulamamızı çalıştıracak komutu belirler. Sanal ortam içerisindeki gunicorn ile çalıştırdığımıza dikkat edin. Burada dikkat edilecek bir diğer nokta run:app
diyerek run.py
içerisindeki app
nesnesine işaret etmiş olmamız. Portuda bir kenara not ediyoruz. Her uygulama için farklı port kullanılması gerekmekte.
4. satıra sunucuya giriş yaptığımız kullanıcının adını giriyoruz.
5. satırda uygulama çökse bile otomatik olarak yeniden başlatmasını söylüyoruz.
9. ve 10. satırlar ise hata logları ile program çıktılarının loglandığı dosyaları işaret ediyor.
Eğer bu işlemleri tamamladıysanız CTRL + X
diyerek dosyamızı kaydediyoruz ve editörden çıkıyoruz. Hata logların basılacağı dosyaları oluşturuyoruz.
~$ mkdir -p logs/confidant
~$ sudo touch /logs/confidant/confidant.err.log
~$ sudo touch /logs/confidant/confidant.out.log
İkinci Kontrol Noktası
Şimdi supervisor ile çalıştıracağımız uygulamayı test ediyoruz. Öncelikle yapılandırma dosyalarının supervisor tarafından okunabilmesi reload
komutunu veriyoruz ve uygulamamızın çalışıp çalışmadığını görmek için status
komutu ile kontrol ediyoruz.
~$ sudo supervisorctl reload
~$ sudo supervisorctl status
Eğer her şey yolunda ise confidant için running çıktısını ekranda göreceğiz. Hemen tarayıcıdan kontrol edelim. Eğer UFW kurduysanız, yapılandırma dosyasında belirtilen portu (13001) açmayı unutmayın.
~$ sudo ufw allow 13001
Şimdi tarayıcıya sunucu IP adresini ve portu girip programımızı kontrol edebiliriz. Tarayıcıdan http://<sunucu_ip_adres>:13001
adresine gidiyoruz. Uygulama karşımızda ise, ikinci kontrol noktasını da tamamlamış oluyoruz. Şimdi UFW ile portu kapatabiliriz.
~$ sudo ufw delete allow 13001
Supervisor ile uygulamalarımızı kontrol etmek için bilmemiz gereken bir kaç komut bulunuyor. Burada reload
komutu yeni bir yapılandırma dosyası eklediğimizde, var olanı değiştirdiğimizde yada sildiğimizde çalıştıracağımız komuttur. Aynı şekilde restart
komutu ise ismi verilen uygulamayı yeniden başlatır. Uygulamaları başlatmak yada durdurmak için ise start
ve stop
kullanılabilir.
~$ sudo supervisorctl reload
~$ sudo supervisorctl restart <APP_NAME>
~$ sudo supervisorctl start/stop <APP_NAME>
NGINX Kurulumu
Nginx sadece bir web sunucusu değil aynı zamanda ters vekil sunucusu ve yük dengeleyici gibi çeşitli alanlarda kullanılan oldukça gelişmiş bir uygulamadır. Flask uygulamamızı sanal olarak host edebilmemize olanak sağlarken statik dosyalarımızı da yayınlayacak kendisi. Hemen kurulumunu yapalım.
~$ sudo apt install nginx
Artık /etc/nginx/site-enabled
klasörü içerisine yapılandırma dosyalarımızı oluşturabiliriz. Bu klasör içerisinde eklenen dosyalar nginx tarafından kullanılabilir. Ama öncesinde varsayılan yapılandırma dosyasını silmemiz gerekiyor.
~$ sudo rm /etc/nginx/sites-enabled/default
Şimdi nano kullanarak kendi uygulamamızın ismi ile yapılandırma dosyası oluşturabiliriz.
~$ sudo nano /etc/nginx/site-enabled/confidant
Yapılandırma dosyamızın içeriğini oluşturabiliriz artık.
server {
server_name <domain_name_or_server_ip_address>;
location /static {
alias /home/<USER_PATH>/<APP_PATH>/app/static;
}
location / {
proxy_pass http://localhost:<PORT_NUMBER>;
include /etc/nginx/proxy_params;
proxy_redirect off;
}
}
server_name
olarak sitemizin yayın yapacağı domain adresini giriyoruz. Eğer hali hazırda bir domaininiz varsa ve kayıtlarını sunucunuza yönlendirmişseniz domain ismini girebilirsiniz. Eğer domain yoksa sunucu IP adresini girmeniz yeterli.
Statik dosyalarımızın NGINX tarafından sunulmasını istediğimiz için uygulamamızın statik dosya klasörünün yolunu belirtiyoruz.
Ve son olarak, kök dizine gelen istekleri, supervisor tarafından çalıştırılan uygulamamıza iletecek şekilde düzenliyoruz. Port numarasını ise, supervisor yapılandırma dosyasına yazdığımız port numarasını yazıyoruz. Artık CTRL + X
diyerek kaydedebiliriz. Şimdi NGINX servisini yeniden başlatabiliriz.
~$ sudo systemctl restart nginx.service
Eğer UFW kurulumu yaptıysanız, HTTP/TCP servisinede onay veriyoruz (80 numaralı port).
~$ sudo ufw allow http/tcp
Artık tarayıcıdan sunucu ip adresine giderek çalışıp çalışmadığını kontrol edebiliriz. Her şey tamamsa uygulamamız düzgün bir şekilde çalışıyor demektir.
http://<server_ip_address>
Uygulamamızı başarıyla yayına aldık. Biraz yorucu oldu ama deploy etmeyi başardık. Ve yeni uygulamalar eklerken bu kadar uğraşmamıza artık gerek kalmayacak.
Faydalı olmasını umuyorum. Uygulamayı nasıl bir domaine bağlayacağımıza ise bir sonraki konuda değineceğim, o zamana kadar sağlıcakla kalın!