Deploy کردن جنگو + nginx + gunicorn

سلام
دوستان من سعی کردم جنگو رو به وسیله آموزشی که از اقای معین باباپور توی سایت زیرو تو هیرو دیدم دیپلوی کنم ولی متاسفانه مشکلی مشابه دفعه قبل که سعی کردم این کار رو با اموزش سایت دیجیتال اوشن انجام بدم برام پیش اومد.من تمام مراحل رو انجام دادم و آخر کار وقتی که به صفحه لوکال هاست مراجعه کردم با صفحه خوشامدگویی انجینکس مواجه شدم وقتی هم که به هر کدوم از اپ های سایت مراجعه کردم با اخظار ۴۰۴ مواجه شدم.دیمون های گونیکرن و انجینکس فعال هستن و حدس میزنم که مشکل از این دو نیست.
چون هر دو دفعه به مشکل مشابه برخوردم حس میکنم جایی رو اشتباه فهمیدم
ممنون میشم اگه میتونید کمک کنید.

توی این مرحله از کار، هزارتا چیز میتونه مشکل ایجاد کنه. واقعا نمیشه جواب درست و دقیقی داد.
لطفا این فایلها رو به اشتراک بذارید (توی یه gist یا یه همچین جایی باشه بهتره. اگه همینجا paste کنید خوندنش یه کم سخت میشه)

  • کانفیگ nginx
  • کانفیگ gunicorn و لطفا توضیح اینکه چرا از uwsgi استفاده میکنید؟؟؟
  • امیدوارم سیستم‌عاملتون لینوکس باشه. اگه نیست کمکی از من بر نمیاد.

سلام
سیستم عاملم لینوکس هست
فایل هایی مه گفتید بعلاوه فایل settings.py رو تو ادرس https://github.com/devprofile98/django-deploy قرار دادم .
در مورد استفاده از uwsgi هم نمیدونم چون جستجو کردم دیپلوی کردن جنگو با انجینکس چون اکثر نتیجه ها همینو اموزش میدادن برای شروع همینو انتخاب کردم
ادرس پروژه جنگو روی سیستم خودم : /home/sub/Documents/django
ادرس محیط مجازی که استفاپه میکنم: home/sub/virtualenv/firstdeploy/
ممنون از کمکتون

ببخشید دیر پاسخ میدم. امروز خیلی سرم شلوغ بود.

بخش اول

خب مثل اینکه روی سیستم خودتون میخواید دیپلوی کنید. یعنی روی سرور قرارش نمیدید. درسته؟
اگه اینطوریه، پشنهاد میکنم یه دامنه برای وبسایت انتخاب کنید و از 127.0.0.1 استفاده نکنید. مثلا من همیشه home.com رو برای اینکار ست میکنم. برای اینکه این دامنه به ip لوکال اشاره کنه، باید این فایل رو ویرایش کنید:

/etc/hosts

و این خط رو بهش اضافه کنید:

127.0.0.1        home.com

اینطوری دیگه سیستم شما برای resolve این دامنه، به dns serverها مراجعه نمیکنه و خودش ریکوئست رو میفرسته به IP که بش دادید.
توی کانفیگ nginx هم باید بهش بگید که منتظر دریافت ریکوئست از این دامنه باشه (به جای 127.0.0.1 که توی کانفیگ نوشتید)


بخش دوم

مطمئن هستید که فایلی در آدرس /home/sub/Documents/django/firstdeploy.sock وجود داره و nginx پرمیشن خوندن و نوشتنش رو داره؟
از طرف دیگه فکر میکنم توی فایل کانفیگ nginx باید این خط:

proxy_pass http://unix:/home/sub/Documents/django/firstdeploy.sock;

تبدیل بشه به این:

proxy_pass unix:/home/sub/Documents/django/firstdeploy.sock;

اگه مشکل از پرمیشن نیست و فایل هم سر جاش هست و آدرس درسته، پیشنهاد میکنم به جای استفاده از unix socket، از http استفاده کنید.
نمیدونم کانفیگ gunicornش چطوریه ولی آدرسش چیزی شبیه این میشه:

http://0.0.0.0:9876
or
http://127.0.0.1:9876

(با پورت دلخواه. یه پورت بزرگ انتخاب کنید و مطمئن بشید چیزی روی اون پورت وجود نداشته باشه)
این باید توی کانفیگ nginx و خط ۹ از کانفیگ gunicorn ثبت بشه (چطوریش رو نمیدونم. باید داکیومنت gunicorn رو مطالعه کنید)


رفع اشکال

همیشه بهتره کارهای بزرگ رو به قطعات کوچیک و قابل تست تقسیم کنیم. مثلا اول مطمئن بشید که gunicorn.service داره درست کار میکنه و واقعا سیستم رو ران کرده. مثلا چک کردن فایل .sock که میسازه یا پورتی که درست میکنه. چک کردن لاگ‌ها هم میتونه مفید باشه. فایل .service کار خاصی انجام نمیده. برای تست اینکه درست کار میکنه یا نه، اول سرویس رو stop کنید. بعد cd کنید به آدرسی که توی خط WorkingDirectory نوشته شده و کامند ExecStart رو خودتون توی ترمینال اجرا کنید (لازم نیست آدرسها رو به صورت absolute بنویسید) و ببینید چه جوابی میگیرید. ممکنه یه ارور مسخره اینجای کار باشه و کل داستان رو همین خراب کرده باشه.
بعد مطمئن بشید nginx درست کار میکنه و میتونه اون فایل یا پورت رو بخونه. لاگهای nginx رو نگاه کنید. هم access log و هم error log.
بعد آدرس رو توی بروزر وارد کنید و نتیجه رو نگاه کنید. یه وقتایی تست کردنش از طریق ترمینال هم میتونه کمک کنه. با کامندهایی مثل:

curl home.com
curl -I home.com
ping home.com
traceroute home.com

یه نکته‌ی دیگه هم هست که احتمالا مشکل همین باشه. توی کانفیگ gunicorn.service یه خط جاش خالیه. خطی که به systemd میگه که environment ما کجاست. این خط:

Environment="PATH=/home/pouya/project/my-virtualvenv/bin"

جهت رفرنس، این یه کانفیگیه که من برای یکی از پروژه‌های flask نوشتم که با uwsgi ران میشد:

[Unit]
Description=uWSGI instance to serve my project
After=network.target

[Service]
User=pouya
Group=nginx
WorkingDirectory=/home/pouya/my-project
Environment="PATH=/home/pouya/my-project/venv/bin"
ExecStart=/home/pouya/my-project/venv/bin/uwsgi --ini wsgi.ini

[Install]
WantedBy=multi-user.target

و البته این‌هم کانفیگ wsgi.ini که توی فایل بالایی آدرسش نوشته شده:

[uwsgi]
module = wsgi

master = true
processes = 10

socket = 0.0.0.0:9876
vacuum = true

logto = /tmp/my-project.log

die-on-term = true

برای استفاده از uwsgi، یادتون نره اول نصبش کنید:

pip install uwsgi

اصولا خیلی شبیه gunicorn هست فقط کامندهاش یه کم فرق میکنه.

ممنون واقعا به خاطر وقتی که گذاشتید آقای عباسی.
بله برای یادگیریه فعلا به خاطر همین رو سیستم خودم میخام دیپلوی کنم چون هزینه وی پی اس ها زیاده و فکر کنم فرق نداشته باشن این دو حالت باهم یعنی اگه روی لوکال یاد بگیرم با تقریب خوبی روی وی پی اس هم میتونم انجام بدم،
فایل .sock هم ساخته شده ولی دسترسی هاشو چک نکردم.
کارایی که گفتید رو انجام میدم و به احتمال زیاد بازم مزاحمتون میشم،ممنون

احتمالا مشکل از دسترسیه. یا دسترسی خود فایل یا دایرکتوریهای بالاییش. حواستون به این نکته باشه که owner و group فایل، با owner و groupی که nginx با اونها ران شده متفاوته. توی فایل /etc/nginx/nginx.conf میتونید ببینید که با چه یوزری ران میشه.
با پورت هم امتحان کنید. من اغلب از پورت استفاده میکنم.

بله دیپلوی کردن روی سرور تفاوت زیادی نداره بجز بحث ست کردن دامنه، که اونم با ویرایش /etc/hosts میتونید شبیه‌سازیش کنید.

یه توضیحی هم درمورد کل قضیه‌ی serviceهای systemd بدم.
این سرویسها که کانفیگشون رو از فایلهایی با پسوند .service در دایرکتوری /etc/systemd/system/ میخونن، در حقیقت ترمینالهای مجازی ران میکنن برای اجرای کامندی که ما توش تعیین میکنیم، به صورت اتوماتیک.
این توضیح، دقیقترین و کاملترین توضیح ممکن نیست، فقط خواستم بگم که چیز خیلی پیچیده‌ای نیست و کار خیلی خاصی نمیکنه. برای همین توی پست قبلی گفتم که میتونیم این کارها رو به صورت دستی هم انجام بدیم و نتیجش رو ببینیم.


راهنمایی درمورد ارورها

یه سری از ارورهایی که میبینید از طرف nginx ساخته میشن یه سریاشون از طرف نرم‌افزار شما. ظاهرشون میتونه خیلی شبیه به هم باشه. باید یه جوری مطمئن بشید که ارور از کجاست تا راحتتر مشکل رو پیدا کنید و فیکسش کنید.
مثلا اگه ارور 502 داد، توضیحش “bad gateway” هست. یعنی nginx نتونسته به socket شما وصل بشه. اگه ارور 404 بود، نمیشه با اطمینان گفت از کدوم قسمته مگر اینکه هرکدوم ظاهر اروهای ۴۰۴شون با دیگری فرق کنه.
ارورهای nginx رو میتونید توی /var/log/nginx ببینید. خیلی میتونه کمک کنه به پیدا کردن مشکل.

سلام
همونطور که گفتید nginx و gunicorn رو تک تک تست کردم و مشکلی در اجرا نداشتن، بعد توی فایل /etc/hosts یک ادرس جدید با ip لوکال ساختم و توی فایل های کانفیگ تغیرات رو اعمال کردم ولی بازم فایده ای نداشت،تنظیمات پرمیشن ها رو هم مثل متن اموزش انجام دادم ولی بازم وقتی دامنه ای که تعریف کردم (django.man) رو استفاده میکنم صفحه خوشامدگویی nginx رو میاره.وقتی که لاگ فایل انجینکس(var/log/error.log) رو بررسی کردم بازم چیز خاصی نبود انگار که انجینکس اصلا به سروربلاکی که من براش تعریف کردم اهمیت نمیده و سرور دیفالت خودشو اجرا میکنه که توی سایت digital ocean نوشته از server_name هایی استفاده کنیم که مثل دیفالت نیسن و منم همینکارو کردم (django.man) استفاده کردم.
متاسفانه یا خوشبختانه هیچ جای کار حداقل از نظر من و لاگ فایل ها هیچ اروری نیست یا من نمیتونم ببینمش.اگه پیشنهادی دارین واقعا با جان و دل میشنوم.در هر صورت ممنون

1 Like

خب. یه مساله‌ای. کانفیگ nginx کجاست دقیقا؟ توی این آدرسه؟

/etc/nginx/sites-available/my-config

و آیا یه لینک ازش داخل این آدرس قرار دادید؟

/etc/nginx/sites-enabled/my-config

اگه اینکارو نکرده باشید nginx کانفیگ شما رو نمیخونه. برای انجامش باید از این کامند استفاده کنید:

ln -s /etc/nginx/sites-available/my-config /etc/nginx/sites-enabled/my-config

و برای تست درست بودن کانفیگها از این کامند استفاده کنید:

nginx -t

این کامند رو هربار بعد از ویرایش کانفیگها باید اجرا کنید که مطمئن بشید کانفیگها درست هستن، بعدش میتونید systemctl restart nginx یا کامندهای این‌مدلی رو بزنید.


اگه server_name رو روی django.man ست کردید و پورت روی 80 هست، پس nginx منتظر دریافت کانکشن از پورت ۸۰ هست، کانکشنی که درخواست دامنه‌ی http://django.man رو داشته باشه.
اگه میخواید http://www.django.man هم توسط این بلاک پشتیبانی بشه،‌ باید اینم توی خط server_name قرار بدید:

server_name django.man www.django.man other-domain.com www.other-domain.com;

برای اینکه مطمئن بشید لاگهایی که میبینید برای همین ریکوئست آخر هستن، پیشنهاد میکنم کلا لاگهای nginx رو پاک کنید:

rm /var/log/nginx/*

بعد systemctl restart nginx بزنید و بعد یک ریکوئست بزنید به دامنه.
اونوقت تنها لاگی که دیده میشه برای همین یه‌دونه ریکوئسته. برای شما که عادت به خوندن لاگهای nginx ندارید، پیدا کردن مشکل به این روش راحتتره.

در ادامه…

پیشنهاد میکنم یه بار این مسیری که میگم رو طی کنید، حس میکنم اینطوری دستتون توی کانفیگ سرور راه بیفته.
من الآن یه کانفیگ nginx درست کردم توی آدرس /etc/nginx/sites-available/home و محتویاتش اینه:

server { 
  listen 80;         # Listen to ipv4 requests on port 80.
  listen [::]:80;    # Listen to ipv6 requests on port 80.

  server_name home.com www.home.com;    # Only respond to these **TWO** domains.

  location / {
    proxy_pass       http://localhost:8000;    # Pass whatever the request is, to port 8000.
    proxy_set_header X-Real-IP $remote_addr;   # Set some headers.
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
  }
}

و با ln -s یه لینک ازش درست کردم توی آدرس /etc/nginx/sites-enabled/home
وقتی sudo nginx -t میزنم این جواب رو میگیرم:

─$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

پس میتونم nginx رو restart یا reload کنم.

حالا وقتی توی بروزر آدرس home.com رو میزنم، بر فرض اینکه توی /etc/hosts پوینتش کرده باشم روی 127.0.0.1، این جواب رو میگیرم:

502 Bad Gateway
nginx/1.16.1

و البته با curl هم این جواب:

─$ curl -I home.com
HTTP/1.1 502 Bad Gateway
Server: nginx/1.16.1
Date: Sat, 02 Nov 2019 14:50:58 GMT
Content-Type: text/html
Content-Length: 157
Connection: keep-alive

این پاسخ، یعنی nginx داره درست کار میکنه، ولی مشکلی توی پورت 8000 هست. احتمالا چیزی توی اون پورت منتظر ریکوئستهایی که از nginx میاد نیست!

با پایتون، توی کامندلاین میتونم یه سرور ساده ران کنم روی این پورت (کاری که flask و django هم انجام میدن دقیقا همینه) با این کامند:

python3 -m http.server 8000

الآن اگه این آدرس (localhost:8000) رو توی بروزر بزنم، وب‌سروری که ران کردم پاسخ رو نشونم میده و با تشکر از nginx، الآن پورت 80 هم ترافیکها رو پراکسی میکنه به پورت 8000 یعنی اگه توی بروزر home.com رو بزنم هم همین پاسخ رو دریافت میکنم.

سلام اقای عباسی عزیز،ممنون از لطفتون
بر اساس پیشنهاد آخرتون کارهایی که گفتید انجام دادم،ولی بازهم منو به صفحه خوشامد nginx فرستاد.
تصمیم گرفتم یه بار دیگه این مراحل رو از اول انجام بدم، چون جایی خوندم که نصب nginx از طریق ریپو یا اینکه خودم بیلدش کنم میتونه تنظیمات اینکه سایت پیشفرض nginx توی چه مسیری باشه یا اینکه توی بعضی از تنظیمات تغییراتی به وجود بیاره میتونه موثر باشه و چون من از سورس بیلد کردم شاید باعث این مشکل شده که همیشه صفحه خوشامد میبینم.
اگر موفق شدم حتما در جریان قرارتون میدم،موفق باشید

قطعا مشکل همینه. باید ببینید فایلهای کانفیگ کجا هستن. این فایلهایی که من گفتم ویرایش کنید رو اصلا نگاه نمیکنه و جای دیگه ای دنبال کانفیگ میگرده.

شاید کانفیگهاتون اینجا:

/usr/local/nginx/conf/nginx.conf

یا اینجا:

/usr/local/etc/nginx/nginx.conf

یا یه آدرسی شبیه به همینا باشن. اگه نبود، پکیج mlocate رو نصب کنید و بعد از آپدیت کردن دیتابیسش با دستور sudo updatedb، دنبال فایلی به نام nginx.conf بگردید:

locate nginx.conf

اقا من از اول انجام دادم و ایندفعه دیگه بیلد نکردم nginx رو و درست شد.ممنون ازتون که این مدت کمک کردین آخه واقعا هر جا سوال پرسیدم هیچکس جوابمو نمیداد الا شما.:raised_hands:

2 Likes

امید وارم که الان مشکلتون حل شده باشه ولی من به شخص وقتی بخوام یه جنگو ران کنم از این لینک روندو ادامه میدم

1 Like

بله مشکلم حل شد،ممنون
اموزشی که فرستادید ورژن جدیدتری هم داره که فکر کنم بهتره البته تفاوت زیادی نداره:

فکر میکنم جای مناسبی باشه تا این سرویس رو معرفی کنم. یه وبسایته که میشه باهاش کانفیگ nginx ساخت.
چندساله که با nginx کار میکنم و چندتا سرویس روش ران کردم ولی اینجا یه چیزهایی داشت که بلد نبودم!

1 Like