Bloğa geri dön

Ubuntu 20.04 üzerinde PostgreSQL, Nginx ve Gunicorn ile Django Kurulumu

Ubuntu 20.04 üzerinde PostgreSQL, Nginx ve Gunicorn ile Django Kurulumu

Django, Python programlama dilinde oluşturulmuş, ücretsiz ve açık kaynaklı bir web uygulaması çerçevesidir. Django son derece hızlı, güvenli ve yüksek düzeyde ölçeklenebilirdir. Yetenekli bir geliştiricinin elinde Django, hızlı bir şekilde güçlü bir web sitesi kurabilir. Popüler web sunucuları (Apache, Nginx) ve veritabanları (MySQL, MariaDB, PostgreSQL, Oracle ve SQLite) vb. ile sorunsuz bir şekilde entegre olabilir. Django; Instagram, Mozilla ve NASA gibi dünyanın en büyük web sitelerinden bazılarına güç vermektedir. Bu kılavuz, PostgreSQL, Nginx ve Gunicorn yardımıyla Django ile bir web uygulamasının temelini Ubuntu 20.04 üzerinde kurmayı göstermektedir.

Gereksinimler

Bu kılavuz, temel bir güvenlik duvarı ve sudo yetkisine sahip root olmayan bir kullanıcı ile yapılandırılmış bir Ubuntu 20.04 sunucusu çalıştırmanızı gerektirir. Bir Ubuntu sunucusunun nasıl kurulacağına ilişkin bu ayrıntılı kılavuza göz atın. sudo yetkisine sahip root olmayan bir kullanıcıyı yapılandırmak için bu öğreticiyi takip edin. Ayrıca bu kılavuzdaki adımları izleyerek bir Iptables güvenlik duvarı yapılandırabilirsiniz.

. Django'yu sanal bir ortamda kuracağız. Projeye özel bir ortama sahip olmak, aynı sunucudan birden fazla projenin daha kolay yönetilmesini sağlar. Veritabanları ve uygulamalar hazır olduğunda, Gunicorn uygulama sunucusunu dağıtacağız. Gunicorn, istemci isteklerini HTTP'den uygulamamızın kullanabileceği Python çağrılarına dönüştüren uygulama arayüzü olacaktır. Ardından, hızlı performanslı bağlantı yönetimi ve uygulaması kolay güvenlik özellikleri için Gunicorn'un önüne Nginx'i dağıtacağız.

Gerekli Paketlerin Kurulması

İlk olarak, gerekli tüm paketleri kurarak işe başlayın. Neyse ki, tüm bu paketler resmi Ubuntu paket depolarından doğrudan temin edilebilir. Terminali açın ve APT paket önbelleğini güncelleyin:

Paket listesi, web uygulamasının Python 2 mi yoksa Python 3 mü kullanacağına bağlıdır. Django'yu Python 3 ile kurmak için aşağıdaki komutu çalıştırın:

Django 1.11 LTS, Django'nun Python 2'yi destekleyecek son sürümüdür. Django'yu Python 2 ile kullanmak istiyorsanız, aşağıdaki paketleri kurun:

PostgreSQL Veritabanı ve Kullanıcısı

Veritabanı çözümü olarak PostgreSQL kullanacağız. Güçlü, açık kaynaklı bir nesne-ilişkisel veritabanı sistemidir. PostgreSQL güvenilirlik, sağlamlık ve performans sunar. PostgreSQL kurulumuna ilişkin ayrıntılı adımlar için Ubuntu sunucusunda PostgreSQL kurulumu hakkındaki bu kılavuza göz atın. Bu kılavuz için, Django uygulamamız için özel bir veritabanı ve kullanıcı oluşturacağız.

Varsayılan olarak PostgreSQL, yerel bağlantılar için kimlik doğrulama şeması olarak “peer authentication” (eş kimlik doğrulaması) uygular. Kısacası, “peer authentication”, kullanıcının işletim sistemi kullanıcı adı geçerli bir PostgreSQL kullanıcı adı ile eşleşirse girişi doğrular. Kurulum sırasında PostgreSQL, postgres işletim sistemi kullanıcısını, postgres PostgreSQL yönetici kullanıcısına karşılık gelecek şekilde yapılandırdı. Aşağıdaki komutu kullanarak postgres olarak PostgreSQL etkileşimli kabuk oturumuna giriş yapın:

PostgreSQL komut satırına ulaşacaksınız. İlk adım, proje için özel bir veritabanı oluşturmaktır. Gösterim amacıyla veritabanı viktor_project:

Bir sonraki adım, proje veritabanı için özel bir kullanıcı oluşturmaktır. Kullanıcının güçlü bir kullanıcı adı olmalıdır. Gösterim amacıyla kullanıcı adı viktor_project_user:

Şimdi bazı parametreleri değiştireceğiz:

  • Belirli bağlantı parametreleri. Kısacası, her bağlantı kurulduğunda doğru değerleri sorgulamak ve ayarlamak gerekmeyecektir. Bu, veritabanı performansını büyük ölçüde artırır.
  • Varsayılan kodlama: UTF-8. Bu evrensel bir kodlamadır ve Django bunu bekler.
  • Varsayılan işlem yalıtım şeması “read committed” (işlenmişi oku) olarak ayarlanır. İşlenmemiş işlemlerden okuma yapılmasını engeller.
  • Saat dilimi: UTC.

Tüm bu parametre değişiklikleri Django projesinin kendisi tarafından önerilmektedir. Bu değişiklikleri uygulamak için aşağıdaki komutları çalıştırın. Veritabanı kullanıcı adını doğru olanla değiştirmeyi unutmayın:

Veritabanı yöneticisini özel veritabanı kullanıcısı olarak değiştirin:

PostgreSQL ile işimiz şimdilik bitti. PostgreSQL etkileşimli kabuğundan çıkın:

Exit the PostgreSQL interactive shell

Python Sanal Ortamı

Veritabanı hazırlandıktan sonra, artık projenin diğer gereksinimlerini oluşturmaya odaklanabiliriz. Daha kolay yönetim için sanal bir ortam oluşturacağız ve tüm Python gereksinimlerini oraya yükleyeceğiz. Sanal bir ortam oluşturmak için virtualenv'e ihtiyacımız var. Pip ile kolayca kurulabilir.

Aşağıdaki komutlar pip'i yükseltecek ve virtualenv'i kuracaktır. Python 3 için aşağıdaki komutları çalıştırın:

Python 2 için bunun yerine aşağıdaki komutları çalıştırın:

Once virtualenv kurulduktan sonra, sanal bir ortam oluşturma zamanı gelmiştir. Ardından, sanal ortam için özel bir dizin oluşturun:

Bundan sonra, mevcut aktif dizini sanal ortam için ayrılmış dizine değiştirin:

Dizin içinde aşağıdaki komutu çalıştırın. virtualenv aracı, proje adıyla sanal bir ortam oluşturacaktır:

Proje adıyla bir alt dizin oluşturacaktır. Alt dizin, Python'ın yerel bir sürümünü ve pip. Proje için izole bir Python ortamı kurma ve yapılandırma esnekliği sunar.

Aşağıdaki komut sanal ortamı etkinleştirecektir:

activate the virtual environment

Terminal istemi, bir Python sanal ortamı içinde çalıştığınızı gösterecek şekilde değişecektir. Artık sanal ortamda olduğumuza göre, gerekli Python gereksinimlerini kuracağız. Django, Gunicorn ve psycopg2 (PostgreSQL adaptörü) bileşenlerine ihtiyacımız var. Aşağıdaki komut, yerel pip'e bileşenleri kurmasını söyleyecektir:

Python 3 kullanıyor olsanız bile doğru komut pip'tir. Çünkü sanal ortamda pip3, pip olarak yeniden adlandırılır.

Yeni Django Projesi

Python bileşenleri hazır olduğuna göre, gerçek Django proje dosyalarıyla çalışmaya başlayabiliriz.

  • Django projesi oluşturma

Proje dizini zaten oluşturuldu. Django'ya dosyalarını oraya kurmasını söyleyeceğiz. Bu işlem, gerçek kodları içeren ikinci düzey bir dizin oluşturacaktır. Dizin ayrıca bir yönetim betiği de içerecektir. Önemli olan, Django'nun mevcut dizine göre karar vermesine izin vermek yerine hedef dizini açıkça belirtmemizdir:

Django projeyi buna göre oluşturacaktır. İşte odaklanacağımız önemli dosya ve dizinlerden bazıları. Dizin ve dosya adları gösterime göre kullanılmıştır.

  • ~/viktor_project/manage.py: Django tarafından sağlanan proje yönetim betiği.
  • ~/viktor_project/viktor_project/: Django projesini içeren pakettir. __init__.py, settings.py, urls.py, asgi.py ve wsgi.py dosyalarını içermelidir.
  • Proje ayarlarını düzenleme

Proje oluşturulduktan sonra yapılacak ilk şey yapılandırmasını düzenlemektir. Bir metin düzenleyicide settings.py dosyasını açın:

Aradığımız ilk yönerge ALLOWED_HOSTS'tur. Django örneğine bağlanabilecek sunucuları veya alan adlarını tanımlar. Gelen herhangi bir istekte Host başlığı ALLOWED_HOSTS listesiyle eşleşmezse, bir istisna oluşturacaktır. Belirli güvenlik açıklarından kaçınmak için Django tarafından önerilir:

ALLOWED_HOSTS

Odaklanacağımız bir sonraki bölüm DATABASE'dir. Veritabanı erişimini yönetir. Varsayılan olarak, SQLite veritabanı motoru için yapılandırma içerir. Ancak proje için PostgreSQL veritabanını kullanacağız. Django, PostgreSQL ile iletişim kurmak için psycopg2 adaptörünü kullanacaktır:

django 1

Şimdi dosyanın en altına gidin. Statik dosyaların konumunu belirtmek için aşağıdaki satırları ekleyin. Bu, Nginx'in bu öğeler için gelen istekleri işlemesine yardımcı olur:

static

Şimdilik settings.py ile işimiz bitti. Dosyayı kaydedin ve düzenleyiciyi kapatın.

  • İlk proje kurulumunun tamamlanması

Artık ilk veritabanı şemasını ayrılmış PostgreSQL veritabanına taşıyabiliriz. Aşağıdaki komutu çalıştırın:

Ardından, proje için bir süper kullanıcı oluşturmamız gerekiyor. Bir süper kullanıcı oluşturmak için aşağıdaki komutu çalıştırın:

viktor_project

Tüm statik dosyaları settings.py dosyasında belirttiğimiz konumda toplayın. Statik dosyalar, proje dizini altında “static” adında ayrı bir dizinde toplanacaktır:

Şimdi sunucu güvenlik duvarı ile uğraşmamız gerekiyor. Sunucu yapılandırma kılavuzunu takip ettiyseniz, zaten UFW'yi yapılandırmış ve etkinleştirmişsinizdir. 8000 numaralı bağlantı noktası için bir istisna oluşturacağız. Bu, Django'nun kullandığı varsayılan bağlantı noktasıdır. Şunun hakkında daha fazla bilgi edinmek için bu kılavuza göz atın: UFW güvenlik duvarı temelleri ve kullanımı.

Ardından, işlemi doğrulayın:

Son olarak, sunucuyu çalışırken test edebiliriz. Django geliştirme sunucusunu başlatın:

Yapılandırma başarıyla tamamlandıysa, Django geliştirme sunucusu başlamalı ve gelen istekleri kabul etmelidir. Bir tarayıcı açın ve 8000 numaralı bağlantı noktasında sunucunuzun IP/alan adına gidin:

django 2

Django varsayılan dizin sayfasına ulaşmalısınız. Yönetici paneline erişmek için URL'nin sonuna /admin ekleyin. Yönetici paneline yalnızca önceden oluşturduğumuz süper kullanıcı erişebilir:

Giriş yaptıktan sonra, varsayılan Django yönetim arayüzüne yönlendirileceksiniz:

django 3

Şimdilik test etmeyi bitirdik. Sunucuyu durdurmak için terminal penceresinden “Ctrl + C” tuşlarına basın.

  • Gunicorn'u Test Etme

Sanal ortamdan çıkmadan önce, Gunicorn'un uygulamaları sunabildiğinden emin olmak istiyoruz. Bunu test etmenin yolu, projenin WSGI modülünü yüklemek için Gunicorn kullanmaktır.

Gunicorn komutu proje dizini içinde yer alır:

Bu, Gunicorn'u Django'nun çalıştığı aynı arayüzde başlatacaktır. Uygulamayı normal bir web tarayıcısından tekrar test edebiliriz. Gunicorn'un statik CSS içeriklerini nasıl bulacağını henüz bilmemesi nedeniyle yönetim arayüzüne herhangi bir stil uygulanmayacağını unutmayın:

İşiniz bittiğinde, Gunicorn sunucusunu durdurmak için terminal penceresinden “Ctrl + C” tuşlarına basın.

  • Sanal ortamdan çıkış

Django uygulama yapılandırması tamamlandı. Sanal ortamdan çıkmak için aşağıdaki komutu çalıştırın:

Gunicorn Soket ve Servis Dosyaları

Gunicorn'un Django uygulamasıyla etkileşime girebildiğini doğruladık. Ancak, uygulama sunucusunu yönetmek için daha sağlam bir yola ihtiyacımız var. İşte burada devreye systemd giriyor. Systemd, Linux'ta bulunan en popüler init sistemlerinden biridir. İşte hakkında derinlemesine bir rehber: systemd servisleri ve birimleri nasıl yönetilir.

Gunicorn için soket ve servis dosyaları oluşturarak systemd'nin onu bir servismiş gibi yönetmesini sağlayabiliriz. Önyükleme sırasında Gunicorn soketi oluşturulacaktır. Soket, gelen bağlantıları dinleyecektir. Bir bağlantı gerçekleştiğinde, systemd bağlantıyı işlemek için Gunicorn işlemlerini başlatacaktır.

  • Gunicorn soketi

Bir Gunicorn soketi oluşturarak başlayalım. Dosyanın sudo yetkisiyle oluşturulması gerekir:

Dosyanın içine aşağıdaki kodu girin:

Gördüğünüz gibi, kodun üç bölümü vardır.

  • [Unit]: Bu bölüm soketi tanımlar.
  • [Socket]: Soket konumunu tanımlar.
  • [Install]: Bu kısım, systemd'nin soketi doğru zamanda oluşturmasını sağlar.

Dosyayı kaydedin ve düzenleyiciyi kapatın.

  • Gunicorn servisi

Sırada, Gunicorn için bir servis dosyası oluşturacağız. Soket dosyasına benzer şekilde, bunun da sudo yetkisiyle oluşturulması gerekir:

Aşağıdaki kodu girin:

Kod birden fazla bölüm içerir:

  • [Unit]: Bu bölüm meta verileri ve bağımlılıkları belirtir. Ayrıca yalnızca ağ hedefine ulaşıldıktan sonra başlatılacağını açıklar.
  • [Service]: Bu bölüm, işlemin altında çalışacağı kullanıcıyı ve grubu belirtir. Grubun sahipliği, Nginx'in Gunicorn ile iletişim kurabilmesi için “www-data” olarak ayarlanmıştır. Ayrıca çalışma dizinlerini eşler ve başlangıç komutlarını belirtir.
  • [Install]: Bu bölüm, sistem açılışında etkinleştirilirse systemd'ye bu hizmeti neye bağlayacağını söyler. Normal çok kullanıcılı sistem çalışmaya başladıktan sonra başlamalıdır.

Ardından, dosyayı kaydedin ve düzenleyiciyi kapatın.

  • Gunicorn soketini etkinleştirme

Gunicorn soketi kullanıma hazır. Bu nedenle, aşağıdaki komutları çalıştırabilirsiniz. Soketi başlatacak ve etkinleştirecektir. Soket dosyası şurada oluşturulacaktır: /run/gunicorn.sock açılışta. Sokete bir bağlantı yapıldığında, systemd bunu işlemek için Gunicorn hizmetini başlatacaktır:

Gunicorn soketinin durumunu kontrol edin:

Şimdi, soket dosyasının varlığını kontrol edin:

Systemctl'den gelen durum bir hata gösteriyorsa veya gunicorn.sock dosyası bulunamadıysa, bu soketin doğru şekilde oluşturulmadığını gösterir. İpuçları için ayrıntılı günlüğe göz atın:

gunicorn.socket

Olası hatalar için gunicorn.socket dosyasına tekrar bakmayı unutmayın.

  • Soket aktivasyonu

Şimdiye kadar gunicorn.socket başlattık. Ancak, herhangi bir bağlantı isteği olmadan, gunicorn.service etkinleşmeyecektir. Ardından, Gunicorn'un durumunu doğrulayın:

Soket aktivasyon mekanizmasını, curl kullanarak bir bağlantı isteği göndererek test edebiliriz:

Uygulamadan bir HTML çıktısı almalısınız. Bu, Gunicorn'un başarıyla başladığını ve Django uygulamasını sunabildiğini gösterir. Gunicorn hizmetinin mevcut durumunu doğrulayın:

Beklenmeyen bir davranış veya çıktı (bir hata gösteren) varsa, ipuçları için ayrıntılı günlüklere göz atın:

gunicorn.service dosyasında değişiklik yapıldıysa, hizmet tanımını yeniden okumak için arka plan programını (daemon) yeniden yüklemeniz gerekir. Bu ayrıca Gunicorn hizmetinin yeniden başlatılmasını gerektirir:

Nginx'i Yapılandırma

Şimdi, gelen trafiği işleme aktarmak için Nginx'i yapılandıracağız. İlk olarak, Nginx'te yeni bir sunucu bloğu oluşturun:

Ardından, aşağıdaki kodu girin:

 

Yapılandırmada birden fazla blok bulunmaktadır:

  • service: Bu blok, sunucunun normal olarak 80 numaralı bağlantı noktasını dinlemesi gerektiğini ve sunucunun alan adına veya IP adresine yanıt vermesi gerektiğini tanımlar.
  • location: Bu ilk location girişidir. Statik varlıkların nerede bulunacağını tanımlar.
  • location: Bu ikinci location girişidir. Bu blok, standart proxy parametrelerini ve trafiğin Gunicorn soketine nasıl aktarılacağını tanımlar.

Dosyayı kaydedin ve düzenleyiciyi kapatın. Etkinleştirmek için dosyayı “sites-enabled” dizinine bağlayın:

Bundan sonra, Nginx yapılandırmasında herhangi bir sözdizimi hatası olup olmadığını test edin:

Bir hata bulamadıysanız, değişikliği uygulamak için Nginx'i yeniden başlatın:

UFW kurallarını tekrar değiştirmemiz gerekiyor. Artık geliştirme sunucusuna erişime ihtiyacımız yok, bu nedenle 8000 portu için olan istisnayı kaldırabiliriz. Ek olarak, normal trafik için 80 portunu açmak istiyoruz:

Bu güvenlik duvarı kuralı değişikliklerini doğrulayın:

Sunucuya artık normal bir web tarayıcısından erişilebilmelidir.

Sorun Giderme Prosedürleri

Tüm adımlar düzgün bir şekilde takip edildiyse, Django uygulamasına internet üzerinden erişilebilmelidir. Erişilemiyorsa, bu durum kurulumun planlandığı gibi gitmediğini gösterir. Sorunun kaynağını bulmak için sorun giderme yapmamız gerekir.

  • Nginx varsayılan sayfayı gösteriyor

Nginx, uygulama proxy'si yerine varsayılan sayfayı görüntülüyorsa, bu genellikle server_name ifadesinin sunucu bloğunda yanlış yapılandırıldığı anlamına gelir.

Bu örnekte, sunucu bloğu aşağıdaki konumda saklanır:

The server_name girdisi, Nginx'in isteklere yanıt vermek için hangi sunucu bloğunu kullanacağını belirler. Varsayılan sayfa gösteriliyorsa, Nginx muhtemelen isteği açık bir sunucu bloğuyla eşleştirememiştir, bu nedenle bunun yerine varsayılan bloğa geri dönüyordur:

Şu değerin Django projenizin sunucu bloğunda düzgün şekilde yapılandırılıp yapılandırılmadığını kontrol edin: server_name.

  • 502 Bad Gateway

502 Hatası, Nginx'in isteği başarıyla yönlendiremediğini (proxy) gösterir. 502 hatasına yol açabilecek çok çeşitli olası yapılandırma sorunları vardır, bu nedenle düzgün bir şekilde sorun gidermek için ipuçlarına ihtiyacımız var.

İpuçlarının birincil kaynağı Nginx hata günlükleridir. Genellikle, proxy işlemi sırasında sorunlara neden olan koşullara işaret eder. Aşağıdaki komutu kullanarak Nginx hata günlüğünü kontrol edin:

Günlük açıldıktan sonra, sunucuya bir kez daha erişmeyi deneyin. Günlükte yeni bir hata mesajı oluşturmalıdır. Bu, sorunu daraltmaya yardımcı olabilir. İşte birkaç olası mesaj:

  • connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)

Bu, Nginx'in gunicorn.sock dosyasını yapılandırmada tanımlanan konumda bulamadığını gösterir. Konum, site bloğu altındaki proxy_pass yönergesi ile tanımlanır. proxy_pass ifadesinin, gunicorn.socket systemd birimi tarafından oluşturulan gunicorn.sock dosyasının doğru konumunu gösterip göstermediğini kontrol edin:

Eğer gunicorn.sock dosyası /run dizini altında bulunamadıysa, bu systemd'nin bunu oluşturamadığı anlamına gelir. Gunicorn soket dosyası yapılandırma adımlarını yeniden kontrol etmelisiniz.

  • connect() to unix:/run/gunicorn.sock failed (13: Permission denied)

Bu, izin sorunları nedeniyle Nginx'in Gunicorn soketine bağlanamadığını gösterir. İşlem bir sudo kullanıcısı yerine root kullanıcısı olarak gerçekleştirildiyse bu durum yaşanabilir. systemd gunicorn.sock dosyasını başarıyla oluşturmuş olsa da, Nginx bunu kullanamaz.

Olası nedenlerden biri, kök dizin (/) ile gunicorn.sock dosyası arasındaki sınırlı izinler olabilir. Soket dosyasının ve üst dizinlerinin her birinin iznini ve sahipliğini kontrol edin:

İlk sütun dosya iznini açıklar. İkinci sütun kullanıcı sahibini ve üçüncü sütun grup sahibini açıklar. gunicorn.sock dosyasına giden dizinlerden herhangi biri uygun okuma ve yürütme izinlerine sahip değilse, Nginx sokete erişemez.

  • Django'nun “could not connect to the server: Connection refused” hatası göstermesi

Bu, Django'nun PostgreSQL sunucusuna bağlanamadığını gösterir. PostgreSQL sunucusunun çalışır durumda olduğundan emin olun:

Eğer çalışmıyorsa, başlatmak ve etkinleştirmek için aşağıdaki komutları çalıştırın:

sudo systemctl enable postgresql

Hâlâ bu hatayı alıyorsanız, veritabanı kimlik bilgilerinin şunun altında düzgün bir şekilde tanımlandığından emin olun: settings.py:

Daha fazla sorun giderme

Ek sorun giderme işlemleri için çeşitli günlükler (loglar) mevcuttur. Bu günlükler, sorunların kaynaklarını daraltmaya yardımcı olabilir.

Yardımcı olabilecek günlüklerin listesi aşağıdadır:

  • Nginx günlükleri
  • Erişim günlükleri-Nginx
  • Hata günlükleri-Nginx
  •  Uygulama günlükleri-Gunicorn
  •  Soket günlükleri-Gunicorn
Yapılandırmada veya uygulamada herhangi bir güncelleme yaptıktan sonra, değişiklikleri uygulamak için süreçleri yeniden başlatmanız gerekebilir. Django uygulaması güncellendiyse, değişiklikleri almak için Gunicorn sürecini yeniden başlatın:
Gunicorn soket veya servis dosyalarında değişiklik yapılması durumunda, arka plan programını (daemon) yeniden yükleyin ve süreçleri yeniden başlatın:
Nginx sunucu bloğu yapılandırmasında değişiklik yapıldıysa, uygulamaya konulmadan önce test edilmelidir. Ayrıca Nginx'in yeniden başlatılmasını gerektirir:

Son Düşünceler

Bu kılavuz, Django'nun temelinin nasıl atılacağını başarıyla göstermektedir. Django, bir web uygulamasının ortak bileşenlerinin çoğunu sağlayarak benzersiz unsurlara odaklanmanıza olanak tanır. Django projesi sanal ortam içinde çalışacaktır. Gunicorn, istemci istekleri ile Django arasındaki iletişimi yönetir. Son olarak, Nginx istemci bağlantılarını işlemek için bir ters proxy (reverse proxy) görevi görür.

Keyifli çalışmalar!

author

Hark Labs

Yazar · CloudSigma

Preslav Dobrev, CloudSigma'da Kreatif Tasarımcı olarak görev yapmakta olup geleneksel ve yenilikçi pazarlama kanallarını kullanarak tutarlı bir kurumsal kimlik oluşturmaya odaklanmaktadır. Sanatsal vizyonu stratejik pazarlamayla harmanlayarak etkili marka anlatıları oluşturma konusunda oldukça yeteneklidir.

Yorumlar

Henüz yorum yapılmamış. İlk siz olun.