*محمد* در نظر دارد پیکربندی مربوط به *HAProxy* را برای وبسایتی که جدیدا در دست طراحی است انجام دهد. در معماری انجام شده، *HAProxy* به عنوان لودبالانسر/پراکسی، جلوی سرورهایی که برای وب سایت ایجاد شدهاند قرار گرفته است در این پیادهسازی از چندین سرور (*api application* و *nginx webserver*) استفاده شده است و برای پاسخ به درخواستهای وبسایت از این سرورها استفاده میشود.
در وبسایت مورد نظر یک اپلیکیشن با نام *api* که یک *flask api* است وظیفه جواب دادن به درخواستها روی مسیرهای `/games` ، `/auth` و `/mobile` را دارد.
همچنین دو وب سرور *Nginx* وجود دارد که وظیفه جواب دادن به درخواستها روی مسیر روت یا `/` را دارند که به صورت *Fail Over* یکدیگر کار میکنند.
برای دانلود پروژه اولیه روی [این لینک](/problemset/assignments/4367/download_problem_initial_project/136629/) کلیک کنید.
حال از *محمد* خواسته شده تا کارهای زیر را انجام دهد:
1. در *HAProxy* نیاز به پیکربندی داریم که بتوانیم با توجه به بالا بودن هر دو وبسرور *nginx*، برای مسیر روت (یا همان `/`) ابتدا فقط ترافیک به وبسرور با نام `app_primary` ارسال شود و در صورت از دسترس خارج شدن سرور اول ترافیک، به سمت وبسرور دوم با نام `app_secondary` ارسال گردد و زمانیکه مشکل وبسرور اول حل شد ترافیک مجدد فقط به وب سرور `app_primary` ارسال شود.
**توجه داشته باشید:**
* تنظیمات *HAProxy* باید به گونهای باشد که همزمان ترافیک به هر دو وبسرور *nginx* **ارسال نگردد.**
* وبسرورهای *Nginx* روی پورت `80` کار میکنند.
* در تنظیمات *HAProxy* برای وبسرورهای *Nginx* یک *backend* با نام *app* تعریف شدهاست که در باکس زیر جزئیات آن را میبینید:
```config haproxy.cfg file
backend app
http-response add-header x-Server %b/%s
default-server check inter 1s fall 1 rise 3
```
2. در پیکربندی *HAProxy* مسیرهای زیر باید توسط اپلیکیشن مورد نظر(یعنی *api* یا *nginx*) جواب داده شود:
* درخواستهای به `/games` ، `/mobile` و `/auth` باید حتما توسط اپلیکیشن *api* جواب داده شود.
* درخواستها به مسیر روت باید توسط وبسرور *Nginx* جواب داده شود.
3. تمامی درخواستهایی که توسط پلتفرمهای همراه (یعنی موبایل، تبلت و ...) حتما بایستی به مسیر `/mobile` هدایت شوند. و در صورتیکه درخواست مورد نظر از این پلتفرمها نباشد بایستی به مسیر درخواستی خود هدایت شود.
**توجه داشته باشید:**
* در صورتیکه درخواست مورد نظر از پلتفرمهای همراه (موبایل، تبلت و ...) **نباشد** و مسیر مورد نظر در هیچ یک از *backend*ها وجود **نداشته باشد** بایستی توسط *Nginx* پاسخ داده شود و به مسیر روت هدایت شود.
* اپلیکیشن *api* روی پورت `5000` کار میکند.
4. در صورتیکه درخواستی دارای کوئری باشد (به عنوان مثال `/digikala?test=foo`) بایستی به مسیر روت (یا همان *nginx*) هدایت شود.
5. پیکربندی *HAproxy* باید به گونهای باشد وقتی درخواستی با هدر `X-Secret: key BASE64DECODED base64` به *HAProxy* رسید قسمت *BASE64DECODED* از هدر درخواستی به صورت *base64* در هدری با نام `auth-hash` به اپلیکیشن *api* داده شود.
**توجه داشته باشید:**
* اپلیکیشن *api* به این صورت کار میکند که اگر درخواستی با هدر `auth-hash` روی مسیر `/auth` برسد هدر مورد نظر را در خروجی چاپ میکند. در نظر داشته باشید که خروجی چاپ شده حتما بایستی مقدار *base64* کلید مورد نظر در هدر *X-Secret* باشد.
* درخواستهای روی مسیر *auth* به صورت زیر ارسال میشود و دارای هدر *X-Secret* میباشند:
```bash terminal terminal
curl -H "X-Secret: key BASE64DECODED RANDOM_STRING" 127.0.0.1:8080/auth
```
به عنوان مثال برای کلید *BASE64DECODED* باید مقدار زیر چاپ شود:
```
QkFTRTY0REVDT0RFRAo=
```
* هیچ تغییری روی کد اپلیکیشن *api* **نباید** داده شود.
* عبارت بعد از *BASE64DECODED* یک رشته تصادفی میباشد.
* سرویس *HAProxy* در هیچ حالتی نباید خطای `5XX` بدهد و برای هر مسیری (موجود و یا ناموجود) باید ریسپانس کد `200` داشته باشد.
* در تنظیمات *HAProxy* برای اپلیکیشن *api* که یک *Flask api* میباشد *backend* با نام *api* تعریف شده است. در ادامه جزئیات *api* را مشاهده میکنید.
```config haproxy.cfg file
backend api
http-response add-header x-Server %b/%s
default-server check inter 1s fall 1 rise 3
```
* تعداد بکندهای تعریف شده در تنظیمات *HAProxy* نباید بیشتر از دو مورد موجود (*api* و *app*) باشد.
* برای ایجاد پروژه اولیه از یک فایل `docker-compose` استفاده شده است که پورت `8080` برای *HAProxy* پابلیش شده است که درخواست های به پورت `8080` هاست (یا همان سیستم شما)، به *HAProxy frontend* روی پورت `80` ارسال میشوند. در ادامه جزئیات *frontend* را مشاهده میکنید:
```config haproxy.cfg file
frontend http
bind *:80
```
تنظیمات *HAProxy* به شرح زیر میباشد:
```config haproxy.cfg file
# haproxy.cfg
global
user root
group root
daemon
stats timeout 30s
defaults
log global
mode http
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http
bind *:80
backend api
http-response add-header x-Server %b/%s
default-server check inter 1s fall 1 rise 3
backend app
http-response add-header x-Server %b/%s
default-server check inter 1s fall 1 rise 3
```
**نکته:** در تعریف *backendها* در *HAProxy* در نظر داشته باشید که اپلیکیشن *api* روی پورت `5000` کار میکند و وبسرورهای *nginx* روی پورت `80` کار میکنند.
## اجرای پروژه اولیه
برای اجرای از دستور زیر استفاده کنید:
```bash terminal terminal
docker-compose up -d
```
برای از دسترس خارج کردن *app* وبسرور *nginx* میتوانید از دستور زیر استفاده نمایید:
```bash terminal terminal
docker-compose stop app_primary
```
برای انجام تست دسترسی به مسیرهای مورد نظر از مرورگر خود آدرس `127.0.0.1:8080` را باز نمایید به عنوان مثال:
```
http://127.0.0.1:8080/
http://127.0.0.1:8080/mobile
http://127.0.0.1:8080/games
http://127.0.0.1:8080/auth
```
برای تست مسیر `/auth` میتوانید از دستور زیر استفاده کنید:
```bash terminal terminal
curl -H "X-Secret: key BASE64DECODED RANDOM_STRING" 127.0.0.1:8080/auth
```
## نحوهی ارسال جواب
شما فقط میتوانید محتوای فایل `haproxy.cfg` را تغییر دهید. تغییرات خودتان را بر روی `haproxy.cfg` اعمال کنید و این فایل را *Zip* کرده و ارسال کنید. توجه کنید که پس از *extract* نمودن فایل زیپ، باید فایل `haproxy.cfg` مشاهده شود.