Flask Projesini Ubuntu Server Üzerinde Yayınlamak
Tags: flask, nginx, supervisor, tutorial
Published: 2022-03-28 19:37:46

Herkese selam!
Flask ile geliştirilmiş bir web uygulamasının bir Ubuntu server üzerinde nasıl yayına alınacağını bu yazıda detaylı anlatacağım. İlk konfigürasyon süreci biraz uzun ve sıkıcı olsa da sunucuyu bir kez konfigüre edince yeni projeler eklemek oldukça kolay olacaktır.

Haydi başlayalım o zaman!

## Proje Yapısı ve Gereksinimler
Genel manada bir web uygulaması birkaç servisten oluşur ve bu servislerin yönetimi ise çeşitli uygulamalar ile sağlanabilir. Kabaca servisler ve bizim bu servisleri yöneteceğim uygulamalar ise aşağıdaki gibidir.

- **Web Servisi (Flask uygulamasının kendisi):** Flask APP
- **WSGI Servisi (Projemizi yayınlayacak servis):** [Gunicorn](https://gunicorn.org)
- **Process Control Servisi (Uygulamamızı çalışır durumda tutacak ve loglayacak servis):** [Supervisord](https://supervisord.org)
- **HTTP Server (Proxy görevi görecek ve statik dosyalarımızı yayınlayacak servis):** [Nginx](https://www.nginx.com/)


![Deploy Schema](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/idhmip1oqtrd56loyxba.png)

Flask APP olarak, daha önce günlük yazmak için geliştirdiğim [Confidant](https://github.com/emregeldegul/Confidant) uygulamasını kullanacağım. Bu uygulama Application Factory modeli ile geliştirildi ve deploy etmek için oldukça uygun.

Son olarak, port yönetimi için ise UFW uygulamasını kullanacağız. Haydi başlayalım.

## Kurulum
## İlk İşlemler
Not: Kurulumu root kullanıcısı dışında bir kullanıcı ile yapılması önerilir. (bknz: [ubuntu kullanıcı oluşturma](https://www.bayramucuncu.com/ubuntu-yeni-kullanici-ekleme-islemleri/))

SSH bağlantısı ile sunucumuza bağlandıktan sonra paketlerimizi güncelleyerek kuruluma başlıyoruz.

`~$ sudo apt update && apt upgrade`

Daha sonra Python, PIP, GIT ve virtualenv kurulumlarını gerçekleştiriyoruz.

`~$ sudo apt install python3 python3-pip git`
`~$ pip3 install virtualenv`

### Flask APP Kurulumu
Artık flask uygulamamızı kurabiliriz. Ev dizinine (`/user/home/`) Flask uygulamamızı git ile klonluyoruz ve uygulama dizinine giriyoruz.

`~$ git clone https://github.com/emregeldegul/confidant && cd confidant`

Daha sonra python uygulamamızı sistemden izole çalıştırabilmek için **virtualenv** ile sanal bir ortam oluşturuyoruz ve bu ortamı aktif ediyoruz.

`~$ python3 -m virtualenv venv && source venv/bin/active`

Artık uygulamamız için gerekli olan paketleri `requirements.txt` dosyasından yüklüyoruz.

`(venv) ~$ pip install -r requirements.txt`

Burada, `requirements.txt` dosyası içerisinde `gunicorn` modülünün de olduğunu unutmayın. Böylece WSGI uygulamasını da aradan çıkartmış olduk.

Uygulama migration dosyaları içerdiğinden küçük bir migration işlemi de yapıyoruz (yoksa, bu adımı geçebiliriz).

`(venv) ~$ flask db migrate`

Uygulamamızın kurulumu tamam.

### UFW Kurulum ve Kullanımı
UFW, basit bir güvenlik duvarı yönetim aracıdır. UFW kullanarak portları güvenli bir şekilde açıp kapatabiliriz.

UFW aracını kurduktan sonra default olarak bir kaç ayar giriyoruz. Ayrıca SSH erişimine izin vermek için SSH portuna erişim izni veriyoruz. Birde flask uygulamamızı test etmek için kısa süreliğine 5000 portunu da aktif ediyoruz. Bu portu daha sonra sileceğiz.

```bash
~$ 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
```

UFW enabled demeden önce ssh'a erişim vermeyi unutmayın. Yoksa sunucu erişimini kaybedersiniz.

Şimdi Flask uygulamamızı uygulama dizini içerisinde sanal ortam ile çalıştırıp erişim sağlamaya çalışıyoruz.

`(venv) ~$ flask run --host=0.0.0.0 --port=5000`

Sunucu IP Adresi ve 5000 portu ile tarayıcı üzerinden bağlanmaya çalışıyoruz.

`http://sunucu_ip_adresi:5000`

Her şey tamam ise uygulamamız bizi düzgün bir şekilde karşılayacaktır. Aksi durumda adımlardan birinde bir hata yapmışız demektir.

`CTRL + C` diyerek flask uygulamasını durduruyoruz ve supervisor ile çalışır hale getirmek için sonraki adıma geçiyoruz.

### Supervisor Kurulumu
Supervisor uygulamamızı sürekli ayakta tutacak ve süreci yönetecek güzel bir araç olarak karşımıza çıkıyor.


![Supervisor Web Interface](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1lacttxqtk6rsvoug8e.png)


Hemen kuruluma başlayalım.

`~$ sudo apt install supervisor`

Supervisor, `/etc/supervisor/conf.d/` içerisinde ayar dosyalarını arayarak süreçleri yönetir. Bizde bu klasör içerisine uygulamalarımızı nasıl çalıştırılacağını beliren`*.conf` dosyaları oluşturarak supervisor'e uygulamamızı tanıtacağız.

`~$ sudo nano /etc/supervisor/conf.d/confidant.conf`

Uygulama ismi ile .conf dosyası oluşturuyorum Nano editör yardımı ile. İçerisine aşağıdaki şekilde ayarları giriyorum.

```
[program:confidant]
directory=/home/user/confidant
command=/home/user/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/logs/confidant/confidant.err.log
stdout_logfile=/home/user/logs/confidant/confidant.out.log
```

Kaydetmek için `CTRL + X` diyorum ve `enter` diyerek değişiklikleri kaydediyorum.

`[program:APP_NAME]`: uygulamamızın ismi. Uygulamamızı yönetirken bu isim ile yöneteceğiz.
`directory`: uygulama dizinimiz.
`command`: uygulamamızı nasıl çalıştıracağını belirttiğimiz komut. Kabaca `gunicorn` ile uygulamamızda ki `run.py` dosyasında bulunan `app` değişkenini işaret ediyoruz (app değişkeni, create_app ile oluşturulmuş uygulamayı içerir).
`user`: root yada aktif oturuma sahip kullanıcı adı.
`stderr_logfile`: flask app hata loglarının tutulduğu dosya.
`stdout_logfile`: program çıktılarının kaydedildiği log dosyası.

Burada **13001** portunu belirttiğimizi unutmayın, bunu ilerde kullanacağız.

Eğer Application Factory kullanmıyorsanız, uygulamanın tanımlı olduğu dosya ve değişkeni işaret etmeniz gerekiyor.

```python
app = Flask(__name__)
```

Burada ki app değişkeni, uygulamamız oluyor.

Log dosyalarını oluşturalım şimdi de;

```bash
~$ mkdir -p logs/confidant
~$ sudo touch /logs/confidant/confidant.err.log
~$ sudo touch /logs/confidant/confidant.out.log
```

Ve konfigürasyon dosyamızı supervisor'a yükleyelim.

`~$ sudo supervisorctl reload`

Supervisor, uygulamamızı çalıştırıyor mu diye küçük bir kontrol sağlayalım;

`~$ sudo supervisorctl status`

confidant uygulamamız `running` ise sıkıntı yok demektir.

Şimdi UFW ile 5000 portunu kapatıp 13001 portunu açalım. Bakalım programımız aktif olarak çalışıyor mu.

```bash
~$ sudo ufw delete allow 5000
~# sudo ufw allow 13001
```

Tarayıcıdan 13001 numaralı porta giderek çalışıp çalışmadığını kontrol edeceğiz.

`http://<sunucu_ip_adres>:13001`

Eğer sayfaya ulaşabiliyorsak supervisor konfigürasyonu tamam demektir. 13001 protunu dışarıya kapatabiliriz tekrar.

`~$ sudo ufw delete allow 13001`

Bir kaç küçük supervisor komutu;

```
~$ sudo supervisorctl reload # yeni konfigürasyon dosyalarını içeri aktarır.
~$ sudo supervisorctl restart <APP_NAME> # Belirtilen uygulamayı yeniden başlatır.
~$ sudo supervisorctl start/stop <APP_NAME> # Belirtilen uygulamayı başlatır/durdurur başlatır.
```

Artık Nginx kurulumu ile devam edebiliriz.

### 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. Ayrıca 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`

Hemen arından Ngnix default yapılandırmasını siliyoruz.

`~$ sudo rm /etc/nginx/sites-enabled/default`

Ve kendi yapılandırma dosyamızı oluşturuyoruz.

`~$ sudo nan /etc/nginx/site-enabled/confidant`

İçerisini aşağıdaki gibi dolduruyoruz.

```
server {
    server_name <domain_name_or_server_ip_address>;

    location /static {
        alias /home/<folder>/<project>/app/static;
    }

    location / {
        proxy_pass http://localhost:<port>;
        include /etc/nginx/proxy_params;
        proxy_redirect off;
    }
}
```

Hepsi bu kadar. Port olarak supervisor ayarlarını yaptığımız sırada girdiğimiz port numarasını giriyoruz. Artık Nginx servisini yeniden başlatabiliriz.

`sudo systemctl restart nginx.service`

UFW ile `http/tcp` portlarına da izin veriyoruz (80 portu).

`~$ 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>`

Hepsi bu kadar! Yorucu oldu ama uygulamamızı deploy etmeyi başardık.

Hayırlı olsun!

Sonraki yazıda nasıl kendi alan adımızı sunucuya bağlarız, bundan bahsedeceğim. O zaman kadar, iyi çalışmalar!