1.13
Web Server ও App Server: Nginx, Apache, Caddy ও অন্যান্য
Web Server আসলে কী করে, Apache ও Nginx ভেতরে কীভাবে কাজ করে, App Server ও তাদের Interface, এবং Production-এ এরা কীভাবে একসঙ্গে বসে।
42 মিনিট পড়া + Animation
টিপস: ডটেড-আন্ডারলাইন করা যেকোনো শব্দে ট্যাপ বা Hover করলে তার অর্থ দেখবে।
এই Lesson শেষে তুমি পারবে
- প্রতিটি Request নিয়ে Web Server ঠিক কী করে তা বলতে, এবং Web Server, Application Server, Reverse Proxy ও Load Balancer আলাদা করে চিনতে, এমনকি একটি Program চারটি ভূমিকাই পালন করলেও।
- Apache ভেতরে কীভাবে কাজ করে (Virtual Host, Module,
.htaccess, prefork, worker ও event MPM) এবং Nginx ভেতরে কীভাবে কাজ করে (Master ও Worker, Event Loop,serverওlocationBlock) তা ব্যাখ্যা করতে। - আসল Nginx Config পড়তে ও লিখতে: Static File,
try_files, Reverse Proxy Header, Load Balancing, Caching, Rate Limiting, TLS, এবং Graceful Reload। - Caddy, IIS, LiteSpeed, Tomcat, HAProxy, Envoy, Traefik ও Varnish-কে Request-এর পথে ঠিক জায়গায় বসাতে।
- Application Server কেন দরকার এবং Web Server তাদের সঙ্গে কীভাবে কথা বলে তা ব্যাখ্যা করতে: CGI, FastCGI ও PHP-FPM, WSGI ও ASGI, Rack, Servlet, Kestrel, Node.js।
- Log দেখে 502, 504, 499, 503, 413, 403 ও Redirect Loop নির্ণয় করতে, এবং System Design Interview-তে একটি Production Stack বর্ণনা করতে।
#Web Server আসলে কী করে
Server আসলে কী? Lesson-এ দেখেছ, Server হলো এমন একটি Program যা একটি Port-এ Listen করে আর Client-কে উত্তর দেয়। Web Server সেই ধারণারই একটি Protocol-এর জন্য বিশেষ রূপ: এটি এমন Software যা HTTP-তে কথা বলে। প্রতিটি Request একই পাঁচটি ধাপ পেরোয়:
- Connection গ্রহণ। Server Port 80 (HTTP) ও 443 (HTTPS)-এ Listen করছে। অপারেটিং সিস্টেম TCP Handshake শেষ করে নতুন Connection-টি তার হাতে দেয়। 443-এ Server এরপর নিজের Certificate ও Private Key দিয়ে TLS Handshake করে।
- Request পার্স করা। সে Request Line ও Header পড়ে (
GET /images/logo.png HTTP/1.1,Host: example.com, …), আর Body থাকলে সেটাও। ভুলভাবে গঠিত Request এখানেই 400 দিয়ে বাতিল হয়। - কী করবে ঠিক করা। Configuration দেখে সে
HostHeader মিলিয়ে একটি Site আর Path মিলিয়ে একটি Rule বেছে নেয়, তারপর একটি কাজ ঠিক করে: Disk থেকে File পাঠানো, Request-টি Application-এর হাতে দেওয়া, Redirect করা (301/302), বা প্রত্যাখ্যান করা (403, 404, 413, 429…)। - Response পাঠানো। Status Line, Header (
Content-Type,Content-Length,Cache-Control…) আর Body, দরকার হলে Compress করে। Keep-alive থাকলে Connection পরের Request-এর জন্য খোলা থাকে। - Log করা। Access Log-এ একটি লাইন (কে, কী চাইল, Status, আকার, কত সময়), আর কিছু ভুল হলে Error Log-এ একটি লাইন।
সব আকর্ষণীয় পার্থক্য তৃতীয় ধাপে। Content দুই ধরনের:
- Static Content হলো এমন File যা আগে থেকেই আছে এবং সবার জন্য একই: আগে থেকে বানানো HTML Page, CSS, JavaScript, Image, Font, Video, Download। Web Server এটা Disk (বা Memory) থেকে পড়ে পাঠিয়ে দেয়। এটা খুব দ্রুত, কোনো Programming Language-ই লাগে না।
- Dynamic Content প্রতিটি Request-এর জন্য Code দিয়ে তৈরি হয়: তোমার Feed, Shopping Cart, Search Result, JSON-এ একটি API Response। Web Server একা এটা বানাতে পারে না। সে Request-টি PHP, Python, Ruby, Java, C#, JavaScript বা Go-তে লেখা একটি Application-এর কাছে পাঠায়, যে সাধারণত Database-এর সঙ্গে কথা বলে, তারপর উত্তরটি ফেরত পৌঁছে দেয়।
নিচের পরিস্থিতিগুলো চালাও: একটি Static File-এর Request, একটি Dynamic Page-এর Request, আর প্রতিদিন যেভাবে এগুলো ব্যর্থ হয়।
Web Server-এর ভেতর দিয়ে একটি Request
App Server-এর সামনে Nginx। একটি পরিস্থিতি বেছে নাও: Static File, Dynamic Page, বা প্রতিদিনের কোনো ব্যর্থতা।
পরিস্থিতি
আগে থেকেই থাকা একটি File: Web Server একাই উত্তর দেয়, App-কে ডাকতেই হয় না।
Browser-এর Nginx-এর সঙ্গে আগে থেকেই TCP ও TLS Connection আছে (না থাকলে খোলে)। সে একটি Logo চেয়ে Request পাঠায়।
#চারটি ভূমিকা, প্রায়ই একটি Program
Application-এর সামনের Box-গুলোর জন্য মানুষ চারটি শব্দ ব্যবহার করে, আর একই Software প্রায়ই একসঙ্গে কয়েকটি ভূমিকা পালন করে:
| ভূমিকা | কাজ | সাধারণ Software |
|---|---|---|
| Web Server | HTTP-তে কথা বলে, Static File পাঠায়, নিয়ম প্রয়োগ করে (Redirect, Header, Access) | Nginx, Apache, Caddy, IIS, LiteSpeed |
| Application Server | একটি Language Runtime ধরে রাখে এবং Dynamic Request-এর জন্য তোমার Code চালায় | PHP-FPM, Gunicorn, Uvicorn, Puma, Tomcat, Kestrel, Node.js |
| Reverse Proxy | পেছনের Server-দের হয়ে Request নিয়ে তাদের কাছে পাঠায়; TLS, Caching, Header যোগ করে | Nginx, HAProxy, Envoy, Traefik, Caddy, mod_proxy-সহ Apache |
| Load Balancer | এমন Reverse Proxy যা একাধিক একই রকম Backend-এ Request ভাগ করে এবং অসুস্থগুলো এড়িয়ে চলে | HAProxy, Nginx, Envoy, AWS ALB/NLB, Google Cloud Load Balancing |
একটি Nginx Process একসঙ্গে Disk থেকে /static/ পাঠাতে পারে (Web Server), /api/ তিনটি App Server-এ ভাগ করে পাঠাতে পারে (Reverse Proxy ও Load Balancer) এবং উত্তরগুলো Cache করতে পারে। আবার Tomcat-কে Application Server বলা হয়, কিন্তু সে দিব্যি HTTP-তে কথা বলে, তাই সে Web Server-ও। তোমার Design-এ Box-এর ভূমিকা দিয়ে নাম দাও, Brand দিয়ে নয়।
#সংক্ষিপ্ত ইতিহাস: একটি অফিস কম্পিউটার থেকে C10K সমস্যা
- ১৯৯০, CERN httpd। CERN-এ Tim Berners-Lee প্রথম Browser-এর পাশাপাশি প্রথম Web Server লেখেন।
- ১৯৯৩, NCSA httpd। NCSA-তে লেখা (যে ল্যাব Mosaic Browser-ও বানিয়েছিল)। এটি CGI চালু করে, Web Server-এর একটি Program চালিয়ে তার Output ফেরত দেওয়ার প্রথম প্রচলিত পদ্ধতি।
- ১৯৯৫, Apache। NCSA httpd-এর উন্নয়ন থেমে গেলে একদল Webmaster নিজেদের সংশোধনগুলো (“Patch”) জড়ো করে একসঙ্গে Apache HTTP Server নামে প্রকাশ করেন। বছরখানেকের মধ্যে এটি বিশ্বের সবচেয়ে বেশি ব্যবহৃত Web Server হয়ে যায়, এবং মোটামুটি দুই দশক সেই জায়গায় থাকে। এর শক্তি ছিল Module ব্যবস্থা: যে কেউ নতুন Feature যোগ করতে পারত।
- ১৯৯৯, C10K সমস্যা। Dan Kegel প্রশ্ন তোলেন, একটি Server কীভাবে একসঙ্গে দশ হাজার Client সামলাবে। যে Server প্রতিটি Connection-এর জন্য একটি করে Process বা Thread রাখত, তার Memory অনেক আগেই ফুরিয়ে যেত। উত্তর ছিল Event-driven, Non-blocking I/O: অল্প কয়েকটি Thread, প্রত্যেকে অপারেটিং সিস্টেমের Readiness Notification দিয়ে হাজার হাজার Socket নজরে রাখে (Linux-এ
epoll, FreeBSD ও macOS-এkqueue)। - ২০০৪, Nginx। Igor Sysoev রাশিয়ার ব্যস্ত Portal Rambler সামলাতে Nginx (উচ্চারণ “engine-x”) তৈরি করেন, শুরু থেকেই সেই Event-driven মডেলে। Static File আর Reverse Proxy-র দ্রুত সামনের Server হিসেবে এটি দ্রুত ছড়িয়ে পড়ে। ২০১১ সালে এটিকে ঘিরে একটি কোম্পানি গড়ে ওঠে, ২০১৯ সালে F5 সেটি কিনে নেয়; Nginx এখনো Open Source, আর ২০২৪ সালে একজন মূল Developer FreeNginx নামে একটি Community Fork শুরু করেন।
- ২০১৫, Caddy। Matt Holt Go-তে Caddy লেখেন; Let’s Encrypt বিনামূল্যে Certificate দেওয়া শুরু করার ঠিক পরেই এটি প্রথম জনপ্রিয় Server হয়ে ওঠে যা প্রতিটি Site-এর জন্য স্বয়ংক্রিয়ভাবে HTTPS Certificate নিয়ে আসে।
আজকের চিত্র মোটামুটি এমন, আর প্রতি বছর বদলায়: Nginx ও Apache দুটোই বিপুল সংখ্যক Website চালায়, Nginx এগিয়ে; Cloudflare একটি বড় অংশে দেখা যায়, কারণ সে লাখ লাখ Site-এর সামনে উত্তর দেয়; WordPress Hosting-এর কল্যাণে LiteSpeed শক্তিশালী চতুর্থ; বাকিটা Caddy, IIS, Node.js ও অন্যান্য। জরিপের সংখ্যা মেলে না, কারণ কেউ প্রতিটি Site গোনে (লাখ লাখ Parked Domain-সহ), কেউ শুধু সবচেয়ে ব্যস্তগুলো।
#Apache HTTP Server গভীরে
Apache (Program-টির নাম httpd, Debian ও Ubuntu-তে apache2) নমনীয়, অসাধারণভাবে Documented, এবং এখনো বহু Shared Hosting-এর Default।
#Configuration: Virtual Host, Directory ও Module
মূল File হলো httpd.conf (Red Hat পরিবার) বা apache2.conf (Debian পরিবার)। Debian বাকিটা Folder-এ ভাগ করে: প্রতিটি Site-এর জন্য sites-available/-এ একটি File, a2ensite দিয়ে চালু করা হয় (যা sites-enabled/-এ একটি Link বানায়), আর Module চালু হয় a2enmod দিয়ে।
মূল উপাদানগুলো:
VirtualHostBlock: প্রতিটি Site-এর জন্য একটি Block। Apache IP, Port ওHostHeader (ServerName,ServerAlias) দেখে Block বেছে নেয়, তাই একটি Server শত শত Domain Host করতে পারে।DocumentRoot: যে Folder-এর File ওই Site-এর জন্য পাঠানো হয়।DirectoryBlock (এবংLocation,Files): File System বা URL-এর একটি অংশের নিয়ম: কে Access পাবে,.htaccessপড়া হবে কি না, Directory Listing দেখানো হবে কি না।- Module প্রায় প্রতিটি Feature যোগ করে:
mod_ssl(TLS),mod_rewrite(Regular Expression দিয়ে URL বদলানো ও Redirect),mod_proxyসঙ্গেmod_proxy_httpবাmod_proxy_fcgi(App Server-এ Reverse Proxy),mod_headers(Header যোগ বা বাদ),mod_deflate(gzip),mod_php(প্রতিটি Apache Process-এর ভেতরেই PHP চালায়)।
একটি আসল Site: HTTP থেকে HTTPS-এ Redirect, File আসে public/ থেকে, আর /api/ যায় Port 8000-এর একটি App-এ।
# /etc/apache2/sites-available/example.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/example/public
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
<Directory /var/www/example/public>
Options -Indexes +FollowSymLinks # Directory Listing বন্ধ
AllowOverride None # .htaccess উপেক্ষা (দ্রুততর)
Require all granted
</Directory>
ProxyPass /api/ http://127.0.0.1:8000/
ProxyPassReverse /api/ http://127.0.0.1:8000/
RequestHeader set X-Forwarded-Proto "https"
Header always set X-Content-Type-Options "nosniff"
ErrorLog ${APACHE_LOG_DIR}/example-error.log
CustomLog ${APACHE_LOG_DIR}/example-access.log combined
</VirtualHost>
sudo a2enmod ssl proxy proxy_http headers
sudo a2ensite example
sudo apachectl configtest # চালু Server-এ হাত দেওয়ার আগে "Syntax OK"
sudo systemctl reload apache2 # Graceful: চলমান Request আগে শেষ হয়
#.htaccess: Directory অনুযায়ী Override
.htaccess হলো একটি Content Folder-এর ভেতরে রাখা ছোট Config File। Directory Block অনুমতি দিলে (AllowOverride All বা অনুমোদিত Directive-এর তালিকা), Apache এর ভেতরের Directive-গুলো ওই Folder ও তার নিচের সবকিছুতে প্রয়োগ করে: Rewrite Rule, Redirect, Password সুরক্ষা, নিজস্ব Error Page, Cache Header।
কেন এটা আছে: Shared Hosting-এ শত শত গ্রাহক একটি Apache ভাগ করে, কেউই মূল Config বদলাতে পারে না। .htaccess দিয়ে প্রত্যেক গ্রাহক একটি File Upload করেই নিজের Site নিয়ন্ত্রণ করে, আর পরিবর্তন Reload ছাড়াই পরের Request থেকে কার্যকর হয়। যেমন WordPress তার “Pretty Permalink”-এর Rewrite Rule সেখানেই লেখে।
কেন এতে Performance কমে: Apache এই File-গুলো Cache করে না। প্রতিটি Request-এ তাকে লক্ষ্য Folder এবং Root পর্যন্ত প্রতিটি Parent Folder-এ .htaccess খুঁজতে হয়, যা পায় তা পড়ে পার্স করতে হয়। /blog/2026/10/post.html-এর একটি Request মানে প্রতিবার কয়েকটি বাড়তি File System খোঁজাখুঁজি।
#MPM: Apache কীভাবে অনেক Connection সামলায়
Apache-এর Connection সামলানোর পদ্ধতিও একটি বদলযোগ্য Module, যার নাম MPM (Multi-Processing Module)। ঠিক একটি লোড করতে হয়:
| MPM | মডেল | শক্তি | দুর্বলতা |
|---|---|---|---|
| prefork | কয়েকটি Process, প্রতিটিতে একটি Thread; প্রতি Connection-এ একটি Process | সম্পূর্ণ বিচ্ছিন্নতা; mod_php ও অন্যান্য Thread-safe নয় এমন Library-র জন্য বাধ্যতামূলক | প্রতিটি Process কয়েক Megabyte Memory খায়। ধীর বা অলস Keep-alive Client একটি পুরো Process আটকে রাখে |
| worker | কয়েকটি Process, প্রতিটিতে অনেক Thread; প্রতি Connection-এ একটি Thread | Connection প্রতি অনেক কম Memory | অলস Keep-alive Connection-ও Timeout না হওয়া পর্যন্ত একটি Thread আটকে রাখে |
| event | worker-এর মতো, সঙ্গে প্রতি Process-এ একটি Listener Thread যে অলস Keep-alive Connection নজরে রাখে | Request-এর ফাঁকে Thread মুক্ত হয়ে যায়, তাই অনেক অলস Client-এর খরচ কম। আধুনিক Linux-এ সাধারণ Default | Thread-safe Module লাগে: PHP mod_php-এর বদলে PHP-FPM দিয়ে চলে |
মূল সীমা হলো MaxRequestWorkers (Apache 2.4-এর আগে নাম ছিল MaxClients): একসঙ্গে সর্বোচ্চ কতগুলো Request সামলানো যাবে। prefork-এ এটা Process-এর সংখ্যা; worker ও event-এ Process গুণ ThreadsPerChild। সবাই ব্যস্ত থাকলে নতুন Connection Kernel-এর Listen Queue-তে অপেক্ষা করে এবং একসময় Timeout হয়ে যায়। তখন Apache Log-এ সতর্ক করে যে Server MaxRequestWorkers-এ পৌঁছেছে।
Animation দেখায় কেন এটা গুরুত্বপূর্ণ: দশটি দ্রুত Client যে কারও জন্য সহজ; Keep-alive Connection-এ বসে থাকা এক হাজার ধীর Client মোটেও সহজ নয়।
অনেক Connection: Apache MPM বনাম Nginx
একই Server, Connection সামলানোর চারটি পদ্ধতি। নিচের নতুন ভিজিটরের কী হয়, লক্ষ করো।
পরিস্থিতি
Connection ছোট থাকলে প্রতি Connection-এ একটি Process ভালোই কাজ করে।
prefork MPM-সহ Apache কিছু তৈরি Process রাখে; প্রতিটি একসঙ্গে ঠিক একটি Connection সামলাতে পারে।
#Nginx গভীরে
Nginx একটি লক্ষ্য নিয়ে তৈরি: অনেক Connection, কম Memory, চাপের মধ্যে কোনো চমক নয়। Internet-এ এটিই সবচেয়ে প্রচলিত Reverse Proxy ও Static File Server।
#Master ও Worker
Nginx চালু করলে একটি Master Process আর কয়েকটি Worker Process পাও:
- Master root হিসেবে চলে। সে Configuration পড়ে ও যাচাই করে, Log File খোলে, এবং Port 80 ও 443-এ Listening Socket Bind করে (Linux-এ ১০২৪-এর নিচের Port-এর জন্য root লাগে)। তারপর Worker-দের চালু করে তত্ত্বাবধান করে। নিজে কখনো কোনো Client সামলায় না।
- Worker-রা খোলা Listening Socket উত্তরাধিকারসূত্রে পায়, তারপর একটি সাধারণ User-এ বদলে যায় (
user www-data;বাuser nginx;)। সাধারণত প্রতি Core-এ একটি Worker থাকে (worker_processes auto;)। প্রতিটি Client Connection শুরু থেকে শেষ পর্যন্ত একটি Worker-ই সামলায়।
কোনো Worker Crash করলে Master নতুন একটি চালু করে। কোনো আক্রমণকারী Request পার্সিংয়ে Bug খুঁজে পেলেও সে root অধিকারহীন একটি Process-এ গিয়ে পড়বে। এই ভাগাভাগির কারণেই Reload হয় Graceful, নিচে দেখবে।
Nginx-এর Master ও Worker Process
কেন Nginx root হিসেবে Port 443 Bind করতে পারে, সাধারণ User হিসেবে সেবা দেয়, আর একটি Connection-ও না ফেলে Config বদলাতে পারে।
পরিস্থিতি
Master বিশেষ অধিকারের কাজগুলো একবার করে; Worker-রা root অধিকার ছাড়াই সেবা দেয়।
Admin Service চালু করে। Master Process root হিসেবে চালু হয়।
#Event Loop: কেন Memory প্রায় স্থির থাকে
প্রতিটি Worker একটি Thread, যা একটি Event Loop চালায়। সে কখনো একটি Client-এর জন্য বসে থাকে না। বরং Kernel-কে জিজ্ঞেস করে (Linux-এ epoll, FreeBSD ও macOS-এ kqueue) “আমার হাজার হাজার Socket-এর মধ্যে কোনগুলো তৈরি, বলো”, তারপর প্রতিটি তৈরি Socket-এ ছোট একটু কাজ করে (কিছু Byte পড়া, একটি Header পার্স করা, Response-এর একটি অংশ লেখা) এবং আবার অপেক্ষায় ফেরে। সব Socket Operation Non-blocking: কোনো Socket-এ এখনো Data না থাকলে Call সঙ্গে সঙ্গে ফিরে আসে, Worker পরের কাজে চলে যায়।
অলস একটি Connection (চিন্তারত একটি Keep-alive Client, ফোঁটা ফোঁটা Byte পাঠানো ধীর মোবাইল Client) Nginx-এর কাছে শুধু একটি ছোট Structure আর কিছু Buffer Memory, কিলোবাইটের হিসাবে, কোনো পুরো Process বা Thread নয়। এজন্যই দশ হাজার অলস Connection-এও Nginx-এর Memory প্রায় বদলায় না, আর যে ধীর Client prefork Apache-কে নিঃশেষ করে দিত, Nginx তা গায়েই মাখে না। প্রতি Worker-এর সীমা worker_connections (প্রায়ই ১০২৪ বা তার বেশি রাখা হয়); তাত্ত্বিক মোট সংখ্যা Worker × worker_connections, আর Proxy করা একটি Request দুটি Connection নেয় (Client-এর দিকে একটি, Upstream-এর দিকে একটি)।
#Config-এর গঠন
Nginx Configuration (/etc/nginx/nginx.conf, প্রায়ই conf.d/ বা sites-enabled/-এ include করা File-সহ) হলো Context (Block)-এর একটি Tree, যার ভেতরে ; দিয়ে শেষ হওয়া Directive:
| Context | কী রাখে |
|---|---|
| main (সবার ওপরে) | user, worker_processes, error_log, pid |
events | worker_connections ও Connection সামলানোর Option |
http | সব HTTP Site-এর Setting: MIME Type, Log Format, gzip, Timeout, upstream Block, Cache Zone |
server | একটি Virtual Host: listen, server_name, Certificate |
location | একটি Server-এর ভেতরে একটি URL Path-এর নিয়ম: root, try_files, proxy_pass |
upstream | Load Balancing-এর জন্য Backend Server-দের নামযুক্ত একটি দল |
বাইরের Block-এ সেট করা Directive ভেতরের Block উত্তরাধিকারসূত্রে পায়, যদি না সেখানে বদলানো হয়। এখানে একটি Site-এর সম্পূর্ণ, বাস্তবসম্মত Configuration:
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65s;
server_tokens off; # Version নম্বর লুকাও
client_max_body_size 20m; # Default 1m
log_format main '$remote_addr "$request" $status $body_bytes_sent '
'rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log main;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
upstream app {
least_conn;
server 10.0.1.11:8000 max_fails=3 fail_timeout=10s;
server 10.0.1.12:8000 max_fails=3 fail_timeout=10s;
server 10.0.1.13:8000 backup;
keepalive 32; # App-এর Connection আবার ব্যবহার
}
proxy_cache_path /var/cache/nginx keys_zone=pages:10m max_size=1g inactive=10m;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/s;
server { # HTTP: শুধু Redirect
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
http2 on; # পুরোনো Version: listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/example/public;
location /assets/ { # Fingerprint করা File: এক বছর Cache
expires 1y;
add_header Cache-Control "public, immutable";
}
location = /login {
limit_req zone=login burst=10 nodelay;
proxy_pass http://app;
}
location /api/ {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_cache pages;
proxy_cache_valid 200 1m;
proxy_cache_use_stale error timeout updating;
}
location / {
try_files $uri $uri/ /index.html; # Single-page App-এর Fallback
}
}
}
#Nginx কীভাবে একটি location বেছে নেয়
একটি server-এর ভেতরে ঠিক একটি location একটি Request সামলায়। ক্রমটি নির্দিষ্ট, আর Interview-তে প্রিয় প্রশ্ন:
- Exact Match
location = /login: Path হুবহু এটা হলে এখানেই থামো। - না হলে Nginx সাধারণ Prefix Location-গুলোর (
location /api/,location /) মধ্যে সবচেয়ে লম্বা মিলে যাওয়া Prefix খুঁজে মনে রাখে। সেই লম্বা Prefix-এ^~চিহ্ন থাকলে (location ^~ /assets/) সেটাই সঙ্গে সঙ্গে ব্যবহার হয়, Regular Expression আর দেখা হয় না। - না হলে Nginx Regular Expression Location-গুলো (
~Case-sensitive,~*Case-insensitive) File-এ যে ক্রমে আছে সেই ক্রমে চেষ্টা করে। প্রথম যেটা মেলে, সেটাই জেতে। - কোনো Regular Expression না মিললে মনে রাখা সবচেয়ে লম্বা Prefix ব্যবহার হয়।
তাই /images/a.png-এর জন্য location ~* \.(png|jpg)$ জিতে যায় location /images/-এর ওপর, যদি না তুমি location ^~ /images/ লেখো। File-এর ক্রম গুরুত্বপূর্ণ শুধু Regular Expression-গুলোর মধ্যে।
#Static File পাঠানো
rootURL-কে Path-এ রূপান্তর করে:root /var/www/site;থাকলে URL/css/app.cssহয়ে যায়/var/www/site/css/app.css। (aliasPath-এর মিলে যাওয়া অংশটি জুড়ে না দিয়ে বদলে দেয়; দুটো গুলিয়ে ফেলা 404-এর একটি পুরোনো কারণ।)try_files $uri $uri/ /index.html;একে একে প্রতিটি বিকল্প চেষ্টা করে: File, তারপর Index File-সহ Folder, তারপর একটি Fallback। Fallback হতে পারে একটি File (Single-page App-এর জন্য) বা একটি নামযুক্ত Location যা App-এ Proxy করে (PHP ও Rails-এর প্রচলিত ধরন: “File থাকলে পাঠাও, না থাকলে App-কে জিজ্ঞেস করো”)।sendfile on;Kernel-কে File-এর Data সরাসরি Page Cache থেকে Socket-এ কপি করতে দেয়, Nginx-এর Memory দিয়ে না ঘুরিয়ে (“Zero-copy”)।tcp_nopush-এর সঙ্গে মিলে Header ও File-এর শুরু পূর্ণ Packet-এ যায়।gzip on;(বা আলাদা brotli Module) Text Type তাৎক্ষণিক Compress করে;gzip_static on;আগে থেকে Compress করা.gzFile থাকলে সেটাই পাঠায়, তাতে CPU বাঁচে।- Cache Header:
expiresওadd_header Cache-ControlBrowser ও CDN-কে জানায় একটি File কতক্ষণ রাখা যাবে। Fingerprint করা File (app.3f9a1c.js) এক বছর Cache করা যায়; HTML সাধারণত নয়।
#Reverse Proxy
proxy_pass http://app; Request-টি একটি Upstream Group বা একটি নির্দিষ্ট Address-এ পাঠায় (http://127.0.0.1:3000, বা একটি Unix Socket http://unix:/run/app.sock)। চারটি জিনিস প্রায় সবসময় Configure করতে হয়:
- Header। App দেখে Connection আসছে Nginx থেকে, তাই Nginx যা জানে তা জানিয়ে দেয়:
Host(আসল Host Name),X-Real-IPওX-Forwarded-For(Client IP-এর শৃঙ্খল),X-Forwarded-Proto(Client TLS ব্যবহার করলেhttps)। App-কে এগুলো বিশ্বাস করতে হবে শুধু Proxy থেকে এলে। - Timeout।
proxy_connect_timeout(Connection স্থাপন),proxy_send_timeoutওproxy_read_timeout(App থেকে পরপর দুবার পড়ার মাঝের সময়, Default ৬০ সেকেন্ড)। Read Timeout শেষ হলে Client পায় 504। - Buffering। Default অনুযায়ী Nginx App-এর Response যত দ্রুত সম্ভব Buffer-এ পড়ে নেয় (বড় হলে একটি অস্থায়ী File-এ), তারপর Client-এর গতিতে ধীরে ধীরে তাকে পাঠায়। দামি App Worker ধীর একটি ফোনের অপেক্ষায় না থেকে সঙ্গে সঙ্গে মুক্ত হয়ে যায়। Server-sent Event-এর মতো Streaming Response-এর জন্য এটা বন্ধ করো (
proxy_buffering off;)। Request Body-ও Buffer হয়, তাই App একটি Upload পায় সেটি পুরোপুরি পৌঁছানোর পরেই। - Upgrade। WebSocket-এর জন্য
proxy_http_version 1.1আরUpgradeওConnectionHeader পার করে দিতে হয়।
#Load Balancing
একটি upstream Block Server-দের তালিকা আর একটি পদ্ধতি রাখে:
| পদ্ধতি | Directive | আচরণ |
|---|---|---|
| Round Robin | (Default) | প্রতিটি Request পালাক্রমে পরের Server-এ যায় |
| Weighted | server a weight=3; | weight ৩-এর Server তিনগুণ ভাগ পায়; বড় Machine বা Canary-র জন্য |
| Least Connections | least_conn; | পরের Request যায় সবচেয়ে কম সক্রিয় Connection-ওয়ালা Server-এ; Request-এর সময় ওঠানামা করলে ভালো |
| IP Hash | ip_hash; | Client IP ঠিক করে কোন Server, তাই একজন Client বারবার একই Server-এ যায় (“Sticky”); Session App-এর Memory-তে থাকলে কাজে লাগে |
| Generic Hash | hash $request_uri consistent; | যেকোনো Key; consistent থাকলে নতুন Server যোগ করলে অল্প কিছু Key-ই সরে (Cache-এর জন্য ভালো) |
Open-source Nginx Passive Health Check ব্যবহার করে: একটি Server-এ Connect করা বা তার থেকে পড়া fail_timeout-এর (Default ১০ সেকেন্ড) মধ্যে max_fails বার (Default ১) ব্যর্থ হলে সেটি fail_timeout সময়ের জন্য অনুপলব্ধ চিহ্নিত হয়, তারপর আবার চেষ্টা করা হয়। ব্যর্থ Request-টি পরের Server-এ আবার চেষ্টা করা হয় (proxy_next_upstream, Default অনুযায়ী শুধু Error ও Timeout-এ, নিরাপদ ক্ষেত্রে)। Active Health Check (নিয়মিত /health যাচাই) আছে বাণিজ্যিক Nginx Plus, HAProxy, Envoy ও Cloud Load Balancer-এ।
upstream Block-এ Load Balancing
Nginx-এর পেছনে তিনটি একই রকম App Server। প্রতিটি পরিস্থিতি একটি Balancing পদ্ধতি বা একটি ব্যর্থতা।
পরিস্থিতি
Default: প্রতিটি Request পালাক্রমে পরের Server-এ যায়।
Request ১ যায় app1-এ।
#Caching ও Rate Limiting
proxy_cacheUpstream-এর Response Disk-এ জমা রাখে, তার Index থাকে Shared Memory-তে (keys_zone)। একই Key-র (Default: Scheme, Host ও URI) পরের Request App-কে না ছুঁয়েই Cache থেকে উত্তর পায়।proxy_cache_use_staleApp বন্ধ বা ধীর থাকলে পুরোনো কপি দেয়, আরproxy_cache_lockমেয়াদোত্তীর্ণ একটি Entry নতুন করে আনতে শুধু একটি Request-কে যেতে দেয়, বাকিরা অপেক্ষা করে; এতে App হুড়োহুড়ি (Stampede) থেকে বাঁচে। যে Response Cookie সেট করে বাCache-Control: privateবলে, সেগুলো Default অনুযায়ী Cache হয় না।limit_reqপ্রতিটি Key-র (সাধারণত Client IP) জন্য একটি “Leaky Bucket” ব্যবহার করে:rate=5r/sসঙ্গেburst=10অল্প সময়ের ঝাঁক সহ্য করে, তারপর বাড়তিগুলো প্রত্যাখ্যান করে। Default প্রত্যাখ্যানের Status 503; অনেক Teamlimit_req_status 429;সেট করে, যাতে Client সঠিক “Too Many Requests” দেখে।limit_connপ্রতিটি Key-র একসঙ্গে Connection সংখ্যা সীমিত করে।
#TLS, HTTP/2 ও HTTP/3
ssl_certificate ও ssl_certificate_key Certificate Chain ও Private Key দেখায় (Key File শুধু root পড়তে পারবে, যা Master অধিকার ছাড়ার আগেই খুলে নেয়)। ssl_protocols TLSv1.2 TLSv1.3; পুরোনো Version বন্ধ করে। HTTP/2 চালু হয় http2 on; দিয়ে (পুরোনো Version: listen 443 ssl http2;)। QUIC-এর ওপর HTTP/3 সমর্থিত Version 1.25 থেকে, listen 443 quic; আর সেটা ঘোষণা করা একটি Alt-Svc Header দিয়ে, কারণ Browser প্রথমে TCP দিয়ে Connect করে তারপর Upgrade করে। Nginx নিজে Certificate আনে না; certbot-এর মতো একটি Tool সেগুলো এনে Nginx Reload করে।
#নিরাপদে Config বদলানো: Test ও Graceful Reload
sudo nginx -t # প্রতিটি File পার্স ও যাচাই; ভুল থাকলে তার লাইন দেখায়
sudo nginx -s reload # অথবা: systemctl reload nginx (Master-কে একটি HUP Signal পাঠায়)
Reload-এ Master আবার Configuration পড়ে। বৈধ হলে সে দরকারি নতুন Socket খোলে, নতুন Config নিয়ে নতুন Worker চালু করে আর পুরোনো Worker-দের নতুন Connection নেওয়া বন্ধ করতে বলে; তারা চলমান Request শেষ করে বিদায় নেয়। একটি Connection-ও কাটে না। নতুন Config অবৈধ হলে Master Error Log-এ লেখে এবং পুরোনো Configuration-ই চালিয়ে যায়। তবুও আগে nginx -t চালানো অভ্যাস করো, কারণ এটা সঙ্গে সঙ্গে ভুল দেখায়, আর ভাঙা File নিয়ে restart (বন্ধ করে চালু) করলে তোমার কোনো Web Server-ই থাকবে না। WebSocket-এর মতো দীর্ঘস্থায়ী Connection পুরোনো Worker-কে বাঁচিয়ে রাখে; worker_shutdown_timeout তার সীমা ঠিক করে।
#Nginx PHP চালাতে পারে না: PHP-FPM-এ FastCGI
Nginx-এর ভেতরে কোনো Language Runtime নেই। PHP-র জন্য সে আলাদা একটি PHP Process Pool, PHP-FPM-এর সঙ্গে FastCGI-তে কথা বলে, সাধারণত একটি Unix Socket দিয়ে:
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
প্রতিটি Language-এ একই ধারণা: Nginx File পাঠায় আর বাকি সব একটি App Server-এ Proxy করে (HTTP, FastCGI বা uwsgi Protocol দিয়ে)।
#OpenResty ও Kubernetes-এ Nginx
OpenResty হলো একটি দ্রুত Lua Engine-সহ Nginx, তাই তুমি Event Loop-এর ভেতরেই Lua-তে Request-এর যুক্তি লিখতে পারো: নিজস্ব Authentication, Dynamic Routing, Database-ভিত্তিক Rate Limit। Kong ও অন্যান্য API Gateway এর ওপর তৈরি। Kubernetes-এ Nginx দীর্ঘদিন সবচেয়ে প্রচলিত Ingress Controller ছিল, অর্থাৎ যে Reverse Proxy বাইরের Traffic-কে Host Name ও Path দেখে Service-এ পাঠায়। Community-র ingress-nginx Project-টি ২০২৬ সালে Kubernetes Project অবসরে পাঠিয়েছে; নতুন Cluster সাধারণত Gateway API ব্যবহার করে, Envoy, Nginx (F5-এর নিজস্ব Controller), Traefik বা HAProxy-ভিত্তিক Controller দিয়ে।
নিজেকে যাচাই করোপ্রশ্ন
Nginx-এ location /images/ আছে, আর File-এ তার পরে location ~* \.(png|jpg)$। /images/cat.png কে সামলাবে?
#Apache বনাম Nginx
| Apache | Nginx | |
|---|---|---|
| Architecture | প্রতি Connection-এ Process বা Thread (prefork / worker); event MPM অলস Connection-এর জন্য একটি Listener যোগ করে | নির্দিষ্ট সংখ্যক Single-threaded, Event-driven Worker |
| অনেক Connection-এ Memory | একসঙ্গে Connection বাড়লে বাড়ে (prefork-এ সবচেয়ে বেশি) | প্রায় স্থির: অলস Connection প্রতি কয়েক কিলোবাইট |
| Static File | ভালো | অসাধারণ; এটা ব্যবহারের পুরোনো কারণ |
| Dynamic Content | Process-এর ভেতরেই PHP চালাতে পারে (mod_php), বা App Server-এ Proxy করে | সবসময় Proxy করে: PHP-FPM-এ FastCGI, App Server-এ HTTP |
| Directory অনুযায়ী Config | .htaccess, Reload লাগে না | নেই: সব Config কেন্দ্রীয়, Reload দিয়ে বদলায় |
| Config-এর ধরন | HTML Tag-এর মতো করে লেখা Directive Block; খুব শক্তিশালী mod_rewrite | ;-সহ নেস্টেড Block; Rewrite-এর বদলে location ও try_files |
| Module | বিশাল Ecosystem, চলার সময় LoadModule দিয়ে লোড | অনেকগুলো ভেতরেই; Third-party Module Compile করে বা ঠিক ওই Version-এর জন্য বানানো Dynamic Module হিসেবে লোড |
| আজকের সাধারণ ভূমিকা | Shared Hosting, পুরোনো App, .htaccess লাগে এমন Setup | Reverse Proxy, Load Balancer, Static File, প্রায় যেকোনো Stack-এর সামনে |
একটি প্রচলিত সমন্বয় হলো Apache-এর সামনে Nginx: Nginx TLS Terminate করে, Static File পাঠায়, ধীর Client সামলায় ও Buffer করে, আর শুধু Dynamic Request 127.0.0.1:8080-এ Listen করা Apache-এ Proxy করে, যেখানে পুরোনো একটি PHP Application-এর জন্য .htaccess ও mod_php চলতে থাকে। তখন Apache-এর mod_remoteip X-Forwarded-For থেকে আসল Client IP ফিরিয়ে আনে।
#অন্যান্য Web Server
#Caddy: Default-ভাবেই HTTPS
Caddy হলো একটি একক Go Binary, সঙ্গে ছোট একটি Config File, Caddyfile। এর সবচেয়ে পরিচিত Feature হলো স্বয়ংক্রিয় HTTPS: Config-এর প্রতিটি Site Name-এর জন্য Caddy ACME Protocol ব্যবহার করে Let’s Encrypt থেকে (বিকল্প হিসেবে আরেকটি বিনামূল্যের Certificate Authority থেকে) Certificate আনে, HTTP থেকে HTTPS-এ Redirect করে, এবং মেয়াদ শেষের আগেই Certificate নবায়ন করে। HTTP/2 ও HTTP/3 Default-ভাবে চালু। TLS-সহ একটি সম্পূর্ণ Reverse Proxy:
example.com {
encode gzip zstd
root * /var/www/example/public
reverse_proxy /api/* localhost:8000
file_server
}
Certificate কীভাবে আসে: Certificate Authority-কে যাচাই করতে হয় যে নামটি তোমার নিয়ন্ত্রণে। HTTP-01 Challenge-এ সে Caddy-কে একটি Token দেয়, তারপর http://example.com/.well-known/acme-challenge/<token> আনে; শুধু ওই নামের আসল Server-ই উত্তর দিতে পারে। তাই DNS আগে থেকেই Server-এর দিকে থাকতে হবে আর Port 80 Internet থেকে পৌঁছানো যেতে হবে। বিকল্প হলো TLS-ALPN-01 (Port 443-এ প্রমাণ) আর DNS-01 (তোমার DNS Provider-এর API দিয়ে একটি TXT Record তৈরি করে প্রমাণ; Wildcard Certificate বা বাইরে থেকে পৌঁছানো যায় না এমন Machine-এর Certificate পাওয়ার একমাত্র উপায়)। Let’s Encrypt-এর Certificate এখন ৯০ দিন টেকে, আরও ছোট মেয়াদ চালু হচ্ছে; মেয়াদের প্রায় এক-তৃতীয়াংশ বাকি থাকলে Caddy নবায়ন করে, ৯০ দিনের Certificate-এর জন্য মেয়াদ শেষের মোটামুটি ৩০ দিন আগে।
Caddy নিজেই Certificate আনে (ACME)
Certificate Authority-কে প্রমাণ দেখাতে হবে যে এই Server সত্যিই example.com-এর হয়ে উত্তর দেয়।
পরিস্থিতি
Port 80-এ দেওয়া একটি Token নামটির নিয়ন্ত্রণ প্রমাণ করে।
Caddy চালু হয়ে এমন একটি Site Name দেখে, যার বৈধ Certificate তার কাছে নেই। সে একটি Account Key তৈরি করে নিজে থেকেই কাজ শুরু করে।
#বাকিরা
- Microsoft IIS (Internet Information Services) হলো Windows Server-এ থাকা Web Server। একটি Kernel Driver (
http.sys) Request গ্রহণ করে Application Pool-এর হাতে দেয়; প্রতিটি Pool কিছু Worker Process (w3wp.exe) নিয়ে গঠিত, যেগুলো আলাদাভাবে Recycle করা যায়। এটি ASP.NET Application-এর প্রচলিত ঠিকানা, আর Configure করা হয় একটি গ্রাফিক্যাল Manager বাweb.configFile দিয়ে (এটাই তার.htaccess)। - LiteSpeed Web Server (বাণিজ্যিক) Nginx-এর মতো Event-driven, কিন্তু সরাসরি Apache-এর Configuration ও
.htaccessFile পড়ে, তাই Hosting কোম্পানি গ্রাহকদের কিছু না বদলিয়েই Apache সরিয়ে দিতে পারে। এর বিনামূল্যের সহোদর OpenLiteSpeed-এর নিজস্ব Config Format আছে, তবে.htaccess-এর Rewrite Rule বোঝে। এর ভেতরের Page Cache LSCache-এর একটি জনপ্রিয় WordPress Plugin আছে, এজন্যই WordPress Hosting-এ এটা বেশি দেখা যায়। - Lighttpd (“lighty”, ২০০৩) C10K সমস্যার উত্তর হিসেবে লেখা হয়েছিল: Event-driven ও খুব ছোট। আজ এটা বেশি দেখা যায় Embedded Device ও Router-এ।
- Apache Tomcat একটি Java Servlet Container (নিচে দেখো), যা নিজেও একটি দক্ষ HTTP Server; Jetty ও Undertow-ও তাই।
- Language-এর নিজস্ব Server। Node-এর
httpModule আর Go-এরnet/httpআসল Production Server: Application নিজেই একটি Port-এ Listen করে। Python-এরpython -m http.serverআর PHP-রphp -Sশুধু Development-এর জন্য; তাদের Documentation-ই তা বলে (নিরাপত্তা নেই বললেই চলে, Concurrency সামান্য)।
#Application Server: তোমার Code আসলে যেখানে চলে
Nginx-এর মতো Web Server Python, Ruby, Java বা PHP-র কিছুই জানে না। কাউকে Language Runtime লোড করে রাখতে হয়, তোমার Application Code আর তার Database Connection Memory-তে গরম রাখতে হয়, এবং একটি Request তার ভেতর দিয়ে চালাতে হয়। সেটাই Application Server। দুজনের মাঝখানে থাকে একটি Interface: Request হস্তান্তর আর Response ফেরত পাওয়ার একটি সম্মত পদ্ধতি। এগুলো মোটামুটি এই ক্রমে এসেছে।
#CGI: প্রতিটি Request-এ নতুন Process
CGI (Common Gateway Interface, ১৯৯৩)-তে Web Server প্রতিটি Request-এর জন্য একটি নতুন Process চালু করে, Request-এর তথ্য Environment Variable-এ (REQUEST_METHOD, QUERY_STRING…) আর Body Standard Input-এ দেয়, এবং Program যা Print করে তা Response হিসেবে পাঠায়। সহজ ও যেকোনো Language-এ চলে, কিন্তু প্রতিটি Request-এ Interpreter চালু করা, Code লোড করা আর Database Connection খোলা ধীর, আর হঠাৎ Traffic বাড়লে হঠাৎ অনেক Process। CGI এখন টিকে আছে শুধু ছোট Embedded Tool-এ।
#FastCGI ও PHP-FPM: Process বাঁচিয়ে রাখো
FastCGI দীর্ঘক্ষণ চলা Process-এর একটি Pool রাখে। Web Server একটি Binary Protocol-এ Socket দিয়ে প্রতিটি Request একটি মুক্ত Process-কে পাঠায়, আর Process পরের Request-এর জন্য বেঁচে থাকে। PHP-FPM (FastCGI Process Manager) আজ PHP চালানোর প্রচলিত পদ্ধতি, Nginx, Apache (mod_proxy_fcgi-সহ event MPM) বা Caddy-র পেছনে। Production-এ এর Pool Setting গুরুত্বপূর্ণ:
pm = staticঠিকpm.max_childrenসংখ্যক Process রাখে;pm = dynamicpm.min_spare_serversথেকেpm.max_spare_serversপর্যন্ত অলস রাখে, সর্বোচ্চpm.max_children;pm = ondemandRequest এলে তবেই Process চালু করে আর অলস Timeout-এর পরে বন্ধ করে (নিরিবিলি Site-এ Memory বাঁচে)।pm.max_childrenএকসঙ্গে PHP Request-এর কঠোর সীমা। Memory দেখে এর মান ঠিক করো: খালি RAM ভাগ একটি PHP Process-এর Memory। সব Child ব্যস্ত থাকলে নতুন Request Socket-এ সারিতে দাঁড়ায়; Log বলেserver reached pm.max_children setting, ব্যবহারকারী ধীর Page দেখে, তারপর Nginx দেয় 504 (সারি উপচে পড়লে 502)।pm.max_requestsএতগুলো Request-এর পর একটি Process বদলে নতুন করে, Memory Leak-এর বিরুদ্ধে নিরাপত্তা জাল;request_terminate_timeoutবেশিক্ষণ চলা Request মেরে ফেলে।
#Python: WSGI ও ASGI
- WSGI (Web Server Gateway Interface) Python-এর Standard: App হলো একটি Callable, যা Request-এর Environment নেয় আর Response ফেরত দেয়। একটি Request শেষ না হওয়া পর্যন্ত একটি Worker দখল করে রাখে। Framework: Django, Flask। Server: Gunicorn, একটি Pre-fork Server, যার Master N সংখ্যক Worker Process চালু করে (শুরুর সাধারণ হিসাব ২ × Core + ১) এবং যেগুলো Crash করে বা
--timeout(Default ৩০ সেকেন্ড) পেরোয় সেগুলো আবার চালু করে; আর uWSGI, খুব Configurable কিন্তু এখন শুধু রক্ষণাবেক্ষণ মোডে। - ASGI (Asynchronous Server Gateway Interface) হলো Async উত্তরসূরি: একটি Worker I/O-র অপেক্ষায় থাকা হাজার হাজার Request পালাক্রমে সামলাতে পারে, এবং WebSocket ও দীর্ঘস্থায়ী Connection সমর্থন করে। Framework: FastAPI, Starlette, Django (Async View)। Server: Uvicorn, Hypercorn, Daphne। Production-এ Uvicorn প্রায়ই কয়েকটি Worker Process নিয়ে চলে (তার নিজের
--workersOption, বা Uvicorn Worker Class-সহ Gunicorn-এর অধীনে)।
#Ruby: Rack, Puma ও Unicorn
Rack হলো Ruby-র Interface (Rails, Sinatra)। Rails-এর Default Puma প্রতিটি Process-এর ভেতরে Thread আর কয়েকটি Worker Process (Cluster Mode) একসঙ্গে ব্যবহার করে, তাই সব Core কাজে লাগায় আবার I/O-র অপেক্ষাও কাজে লাগায়। Unicorn একটি কড়া Pre-fork Server, প্রতি Process-এ একটি Request, যা Nginx-এর পেছনে বসার জন্য বানানো, যাতে Nginx তাকে ধীর Client থেকে আড়াল করে।
#Java: Servlet Container ও Application Server
Java Web App Servlet API বাস্তবায়ন করে। একটি Servlet Container (Tomcat, Jetty, Undertow) একটি দীর্ঘক্ষণ চলা JVM-এর ভেতরে চলে, নিজেই HTTP গ্রহণ করে এবং একটি Thread Pool-এ তোমার Servlet ডাকে। আগে App প্যাকেট করা হতো একটি WAR File হিসেবে এবং চলমান Tomcat-এ Deploy করা হতো; এখন Spring Boot সাধারণত Tomcat (বা Jetty, Undertow) একটি চালানোযোগ্য JAR-এর ভেতরে Embed করে, তাই “App-ই Server”। একটি পূর্ণাঙ্গ Application Server (Jakarta EE, আগে Java EE: WildFly / JBoss, WebLogic, WebSphere, GlassFish) Servlet Container-এর ওপর Transaction, Messaging, Connection Pool ও আরও Enterprise Service যোগ করে।
#.NET, Node.js ও Go
- .NET: ASP.NET Core App চলে Kestrel-এ, Framework-এর ভেতরে থাকা দ্রুত Cross-platform Server। TLS, Static File ও Process ব্যবস্থাপনার জন্য একে প্রায়ই Windows-এ IIS-এর পেছনে, বা Linux-এ Nginx বা Cloud Load Balancer-এর পেছনে রাখা হয়।
- Node.js (এবং Next.js, Express, NestJS): Application নিজেই Server। তোমার Code
listen(3000)ডাকে এবং একটি Event Loop-এ, একটি Core-এ চলে। সব Core কাজে লাগাতে কয়েকটি Process চালাও: Node-এরclusterModule, Cluster Mode-এ PM2 (যা Crash হলে আবার চালু করে এবং Downtime ছাড়া Reload করে), অথবা Load Balancer-এর পেছনে কয়েকটি Container। - Go:
net/http-সহ একটি Compile করা Binary; আর কিছু Install করতে হয় না। তবুও TLS, Routing ও কয়েকটি কপি চালানোর জন্য প্রায়ই একটি Load Balancer-এর পেছনে রাখা হয়।
| Language | Interface | সাধারণ App Server | সাধারণত সামনে থাকে |
|---|---|---|---|
| PHP | FastCGI (বা mod_php) | PHP-FPM | Nginx, Apache, Caddy, LiteSpeed |
| Python (Sync) | WSGI | Gunicorn, uWSGI | Nginx |
| Python (Async) | ASGI | Uvicorn, Hypercorn | Nginx, Cloud Load Balancer |
| Ruby | Rack | Puma, Unicorn | Nginx |
| Java / Kotlin | Servlet (Jakarta EE) | Tomcat, Jetty, Undertow (প্রায়ই Spring Boot-এ Embed করা); WildFly, WebLogic | Nginx, Cloud Load Balancer, Apache |
| C# | ASP.NET Core Hosting | Kestrel | IIS, Nginx, Cloud Load Balancer |
| JavaScript / TypeScript | নেই: App নিজেই HTTP-তে Listen করে | Node.js + PM2 বা cluster | Nginx, Cloud Load Balancer, CDN |
| Go | নেই: net/http | Binary নিজেই | Cloud Load Balancer, Nginx |
Web Server কীভাবে তোমার Code-এর সঙ্গে কথা বলে
প্রতি Request-এ একটি Process (CGI) থেকে দীর্ঘক্ষণ চলা Worker-এর Pool পর্যন্ত, আর Pool ফুরিয়ে গেলে কী হয়।
পরিস্থিতি
প্রতিটি Request-এ সম্পূর্ণ নতুন একটি Process: সহজ, কিন্তু চাপের মধ্যে ধীর।
একটি CGI Script-এর Request আসে।
#Request-এর পথে অন্যান্য Software
Web Server-এর সঙ্গে পথ ভাগ করে আরও বিশেষায়িত কিছু Tool:
- HAProxy (High Availability Proxy, ২০০০ থেকে) TCP (Layer 4) ও HTTP (Layer 7)-এর জন্য একটি নিবেদিত Load Balancer। সে File পাঠায় না; সে Balance করে, আর তাতে অত্যন্ত দ্রুত ও নিখুঁত: Active Health Check, প্রতি Server-এর Connection Queue, Rate Limit ও Sticky-র জন্য Stick Table, বিস্তারিত Statistics। এর
PROXY protocolসাধারণ TCP-তে Client IP পৌঁছে দেয়। - Envoy (Lyft-এ তৈরি, এখন Cloud Native Computing Foundation-এর Project) Microservice-এর জন্য তৈরি আধুনিক Proxy। এর Configuration চলন্ত অবস্থায় API দিয়ে বদলানো যায়, যাদের বলে xDS, কোনো Reload ছাড়াই; এজন্যই Istio-র মতো Service Mesh প্রতিটি Service-এর পাশে একটি Envoy Sidecar চালায়: প্রতিটি Call-এর Retry, Timeout, Mutual TLS ও Metrics সে সামলায়। অনেক API Gateway ও Kubernetes Gateway Controller এর ওপর তৈরি।
- Traefik এমন একটি Reverse Proxy যা নিজে নিজেই Service খুঁজে নেয়: Docker Label বা Kubernetes Resource নজরে রাখে, Container চালু-বন্ধ হলে Route তৈরি করে, আর ACME দিয়ে স্বয়ংক্রিয়ভাবে Certificate আনে। ছোট Cluster ও Home Lab-এ জনপ্রিয়।
- Varnish একটি বিশুদ্ধ HTTP Cache (“Web Accelerator”), যা Web Server-এর সামনে বসে, Caching-এর নিয়মের জন্য তার নিজস্ব Configuration Language আছে। সে নিজে TLS Terminate করে না, তাই সাধারণত Nginx, HAProxy বা একটি আলাদা TLS Proxy-র পেছনে বসে।
- Managed সমতুল্য একই কাজ Service হিসেবে করে: AWS ALB (HTTP, Layer 7: Path ও Host দেখে Routing, WebSocket, gRPC) ও NLB (TCP/UDP, Layer 4, স্থির IP, খুব বেশি Throughput), CloudFront ও Cloudflare (CDN, Edge TLS, Caching, WAF), Google Cloud Load Balancing। তোমাকে Patch বা Scale করতে হয় না, কিন্তু একই ধারণাগুলো Configure করতে হয়: Listener, Target Group, Health Check, Timeout।
Kubernetes Ingress Controller একই ধারণা, একটি Cluster-এর জন্য মানিয়ে নেওয়া। Cluster-এর ভেতরে Pod আসে-যায়, তাই তাদের IP একটি Config File-এ লিখে রাখা যায় না। একটি Ingress Controller (বা নতুন, একটি Gateway API Controller) হলো একটি Reverse Proxy (Nginx, Envoy, Traefik, HAProxy, বা একটি Cloud Load Balancer), যা Cluster নজরে রাখে এবং Service বদলালেই নিজের Routing নতুন করে লেখে। Traffic যায়: Cloud Load Balancer → Ingress Controller Pod → Service → Application Pod।
#প্রচলিত Production Stack
| Stack | Request-এর পথ | মন্তব্য |
|---|---|---|
| LAMP | Apache (mod_php বা PHP-FPM) → PHP → MySQL, Linux-এ | ক্লাসিক Shared Hosting Stack; WordPress, অনেক পুরোনো App |
| LEMP | Nginx → PHP-FPM → MySQL, Linux-এ (উচ্চারণ engine-x বলে “E”) | আধুনিক PHP Stack; VPS-এ Laravel, WordPress |
| Python | Nginx → Gunicorn (Django) বা Uvicorn (FastAPI) → PostgreSQL | একই Machine-এ Nginx ও App-এর মাঝে Unix Socket |
| Ruby | Nginx → Puma → Rails → PostgreSQL, Redis | আগে থেকে Compile করা Asset Nginx পাঠায় |
| Java | Nginx বা ALB → Embedded Tomcat-সহ Spring Boot | Load Balancer-এর পেছনে কয়েকটি একই রকম JVM |
| Node.js | Nginx বা ALB → Node + PM2 (Cluster Mode) | Next.js-এর next start একটি Node Server |
| Kubernetes | Cloud Load Balancer → Ingress / Gateway → Service → Pod (প্রত্যেকটির নিজস্ব App Server) | Rolling Deploy ধীরে ধীরে Pod বদলায় |
| Serverless | CloudFront → Lambda (আর Static File-এর জন্য S3) | সামলানোর মতো কোনো Web Server-ই নেই |
শেষ সারিটি এই Site নিজেই যেভাবে চলে: OpenNext Next.js App-কে CloudFront-এর পেছনে AWS Lambda-র জন্য প্যাকেট করে। কোথাও কোনো Nginx নেই; CloudFront TLS Terminate করে ও Cache করে, S3 Static File পাঠায়, আর Lambda প্রতিটি Request-এ App Code চালায়।
একটি Production Web Stack
প্রতিটি Box-এর একটি কাজ। একটি Dynamic Page, একটি Static File, একটি Node-এর ব্যর্থতা আর একটি Rolling Deploy অনুসরণ করো।
পরিস্থিতি
TLS কোথায় শেষ, কে কী দেখে, আর কোন Box কাজটা করে।
প্রতিটি Hop-এ Encryption
User → CDN
TLS 1.3, Public Certificate
CDN → LB
—
LB → App
—
ব্যবহারকারীর Browser নিকটতম CDN Edge-এর সঙ্গে TLS খোলে। প্রথম TLS Termination এখানেই হয়, ব্যবহারকারীর কাছে, তাতে Round Trip বাঁচে।
#যখন কিছু ভুল হয়
এই স্তরের বেশিরভাগ Incident হাতে গোনা কয়েকটি Status Code হিসেবে দেখা দেয়। কোনটা কে তৈরি করে শিখে নাও, তাহলে কোথায় খুঁজতে হবে বুঝবে।
| লক্ষণ | মানে কী | সাধারণ কারণ | সমাধান |
|---|---|---|---|
| 502 Bad Gateway | Proxy Upstream থেকে কোনো বৈধ Response পায়নি | App Crash করেছে বা চালুই হয়নি; ভুল Port বা Socket Path; Connection refused; Unix Socket খোলার অনুমতি Nginx-এর নেই (Permission denied); Request-এর মাঝপথে App Worker মারা গেছে (যেমন Gunicorn Timeout, Memory শেষ); সব Upstream ব্যর্থ চিহ্নিত (no live upstreams) | App চলছে কি না এবং proxy_pass যেখানে দেখায় সেখানে Listen করছে কি না দেখো; Nginx-এর Error Log ও App-এর নিজের Log পড়ো; Socket-এর Owner/Permission ঠিক করো |
| 504 Gateway Timeout | Upstream গ্রহণ করেছে কিন্তু সময়মতো উত্তর দেয়নি | ধীর Database Query; বাইরের API ঝুলে আছে; Worker Pool শেষ, তাই Request সারিতে | ধীর অংশ খুঁজে বের করো (Log-এ $upstream_response_time); ঠিক করো বা Background Job-এ সরাও; কাজটা সত্যিই লম্বা হলে তবেই proxy_read_timeout বাড়াও |
| 499 (শুধু Nginx Log-এ) | Nginx উত্তর দেওয়ার আগেই Client Connection বন্ধ করেছে | ব্যবহারকারী হাল ছেড়েছে; মোবাইল Network কেটে গেছে; সামনের Load Balancer আগেই Timeout হয়েছে | সাধারণত Upstream-এর ধীরগতির লক্ষণ; ওই লাইনগুলোর সময় দেখো |
| 503 Service Unavailable | ইচ্ছাকৃত “এখন না” | Maintenance Page; limit_req প্রত্যাখ্যান করছে (Default Status); HAProxy বা Cloud Load Balancer-এর কোনো সুস্থ Backend নেই | Health Check ও Rate Limit দেখো; আলাদা করে চিনতে limit_req_status 429 সেট করো |
| 413 Request Entity Too Large | Body অনুমোদিত সীমার চেয়ে বড় | Upload Endpoint-এ client_max_body_size (Default 1m); App ও Load Balancer-এরও সীমা থাকে | সীমা বাড়াও নির্দিষ্ট location-এ, সবখানে নয় |
| 403 Forbidden | Server পাঠাতে অস্বীকার করছে | Worker User File পড়তে বা কোনো Parent Folder-এ ঢুকতে পারছে না; Index File ছাড়া Folder চাওয়া হয়েছে আর Listing বন্ধ (directory index ... is forbidden); deny Rule | Permission ঠিক করো (www-data-র জন্য Folder-এ Execute, File-এ Read লাগে); একটি Index File যোগ করো |
| আছে এমন File-এ 404 Not Found | ভুল Path Mapping | root আর alias গুলিয়ে ফেলা; মিলে যাওয়া location-এ ভুল root; Fallback ছাড়া try_files | Error Log-এ open() ... failed (2: No such file or directory) দেখো: ঠিক কোন Path চেষ্টা করা হয়েছে তা ছাপা থাকে |
TLS Terminate করা Proxy-র পেছনে Redirect Loop (ERR_TOO_MANY_REDIRECTS) | App ভাবে Request HTTP ছিল, তাই HTTPS-এ Redirect করে, অনন্তকাল | Proxy App-এর সঙ্গে সাধারণ HTTP-তে কথা বলে আর X-Forwarded-Proto: https পাঠায় না, বা App তা বিশ্বাস করে না | Header পাঠাও এবং Framework-কে Proxy বিশ্বাস করতে Configure করো (Django SECURE_PROXY_SSL_HEADER, Express trust proxy, Rails config.assume_ssl); CDN-এর TLS Mode-ও দেখো |
Too many open files / worker_connections are not enough | File Descriptor বা Connection Slot শেষ | প্রতিটি Connection একটি File Descriptor (Proxy করলে দুটি); OS-এর সীমা (ulimit -n) worker_connections-এর প্রয়োজনের চেয়ে কম | worker_rlimit_nofile আর Service-এর LimitNOFILE বাড়াও, তারপর worker_connections |
| ধীর Page, তারপর 504/502, CPU কম | Worker Pool শেষ | সব PHP-FPM Child বা Gunicorn Worker ধীর Request-এ ব্যস্ত; নতুনগুলো সারিতে | ধীর Request খুঁজে বের করো; RAM অনুমতি দিলে তবেই Worker বাড়াও; Timeout দাও যাতে আটকে যাওয়া একটি Call চিরকাল একটি Worker ধরে না রাখে |
প্রতিটি Response-এ Server: nginx/1.24.0 | Version ফাঁস | Default server_tokens on (Apache: ServerTokens Full) | server_tokens off; (Apache: ServerTokens Prod, ServerSignature Off) |
#Log পড়া
Access Log বলে কী ঘটেছে, Error Log বলে কেন। ওপরের Config-এর Log Format অনুযায়ী:
# /var/log/nginx/access.log
203.0.113.7 "GET /api/orders HTTP/2.0" 200 1532 rt=0.084 urt=0.081
203.0.113.7 "GET /assets/app.3f9a1c.js HTTP/2.0" 200 48211 rt=0.002 urt=-
198.51.100.4 "POST /api/upload HTTP/2.0" 413 183 rt=0.000 urt=-
192.0.2.55 "GET /api/report HTTP/2.0" 504 167 rt=30.001 urt=30.001
# /var/log/nginx/error.log
connect() failed (111: Connection refused) while connecting to upstream, upstream: "http://10.0.1.12:8000/api/orders"
upstream timed out (110: Connection timed out) while reading response header from upstream
client intended to send too large body: 52428800 bytes
connect() to unix:/run/php/php8.3-fpm.sock failed (13: Permission denied) while connecting to upstream
urt=- মানে কোনো Upstream জড়িত ছিল না (Static File, বা শুরুতেই প্রত্যাখ্যান)। যে Request-এ rt urt-এর চেয়ে অনেক বড়, তার সময় গেছে ধীর Client-এর সঙ্গে কথা বলতে, App-এর অপেক্ষায় নয়। কাজের অভ্যাস: সমস্যা ঘটানোর সময় দুটো File-ই tail -f দিয়ে দেখো, awk দিয়ে Status Code গোনো (নিচে “নিজে করে দেখো” অংশ দেখো), আর প্রতিটি ব্যর্থ Upstream Call দেখতে grep upstream error.log।
#ধীর Client ও Slowloris
Slowloris Attack অনেকগুলো Connection খোলে এবং Request Header খুব ধীরে পাঠায়, কয়েক সেকেন্ড পরপর কয়েক Byte, কখনো শেষ করে না। যে Server প্রতি Connection-এ একটি Process বা Thread রাখে (Apache prefork, আর কিছুটা কম worker), কয়েকশো এমন Connection-এই তার Worker শেষ হয়ে যায়, অথচ আক্রমণকারীর Bandwidth প্রায় লাগেই না। Event-driven Server (Nginx, অলস Keep-alive-এর জন্য Apache event, Caddy, HAProxy) প্রতিটি অপেক্ষমাণ Connection-কে একটি ছোট Structure হিসেবে রাখে, তাই আক্রমণে তার খরচ সামান্য; Timeout (client_header_timeout, client_body_timeout, Apache-এর mod_reqtimeout) আর IP প্রতি Connection-সীমা বাকিটা বন্ধ করে। একই কারণে সামনে একটি Proxy থাকলে প্রতিটি App Server উপকৃত হয়: ধীর অংশটা সে-ই সামলায়।
নিজেকে যাচাই করোপ্রশ্ন
ব্যবহারকারীরা 502 Bad Gateway দেখছে। Nginx Error Log বলছে “connect() failed (111: Connection refused) while connecting to upstream”। সম্ভাব্য কারণ কী?
#Performance ও নিরাপত্তার Checklist
Performance
- Client-এর জন্য (
keepalive_timeout) ও Upstream-এর জন্য (upstreamBlock-এkeepaliveসঙ্গেproxy_http_version 1.1) Keep-alive চালু রাখো, যাতে Connection ও TLS Handshake আবার ব্যবহার হয়। - Compression: Text Type-এর জন্য gzip বা brotli;
gzip_staticদিয়ে আগে থেকে Compress করা File। - Caching Header: Fingerprint করা Asset-এর জন্য
immutable-সহ লম্বাCache-Control, HTML-এর জন্য ছোট বাno-cache; Static File-এর জন্য সামনে একটি CDN। - Static File-এর জন্য
sendfileওtcp_nopush; অনেক ছোট File-ওয়ালা ব্যস্ত Site-এopen_file_cache। - সবখানে HTTP/2, যেখানে Client উপকৃত হয় সেখানে HTTP/3 (মোবাইল, Packet হারানো Network)।
- TLS: শুধু TLS 1.2 ও 1.3, আধুনিক Cipher, Session Resumption, সবখানে HTTPS চালু হয়ে গেলে HSTS।
- ঠিক মাপের Pool:
worker_processes auto, File Descriptor সীমা, Memory ও CPU দেখে App Worker-এর সংখ্যা, Load Test দিয়ে মেপে নেওয়া।
নিরাপত্তা
- অধিকারহীন Worker: শুধু Master root হিসেবে চলে; App Server চলে তাদের নিজস্ব User হিসেবে।
- Version লুকাও:
server_tokens off,ServerTokens Prod, App থেকেX-Powered-Byসরাও। - Request-এর সীমা:
client_max_body_size, Header-এর আকারের সীমা, Login ও ব্যয়বহুল Endpoint-এlimit_req, IP প্রতিlimit_conn। - Timeout: ধীর Client-এর বিরুদ্ধে ছোট Header ও Body Timeout; স্তরে স্তরে সাজানো Upstream Timeout।
- Directory Listing বন্ধ (
autoindex off,Options -Indexes) এবং লুকানো File নিষিদ্ধ (location ~ /\. { deny all; }, তবে/.well-known/খোলা রাখো)। - Security Header:
X-Content-Type-Options,Content-Security-Policy,Referrer-Policy, HSTS। - Forwarded Header বিশ্বাস করো শুধু নিজের Proxy থেকে (Nginx
set_real_ip_from, Apachemod_remoteip)। - হালনাগাদ রাখো, আর প্রতিটি Config পরিবর্তন Graceful Reload-এর আগে Test করো (
nginx -t,apachectl configtest)।
#System Design-এ Web ও App Server
Interview-তে Request-এর পথ আঁকো এবং প্রতিটি Box-এর নাম দাও তার ভূমিকা দিয়ে:
Client ─► DNS ─► CDN (Static File, Edge TLS, Cache)
─► Load Balancer (TLS Termination, Health Check) ┐ Stateless,
─► Web Tier: Nginx (Static, Buffering, সীমা, Routing) │ LB-এর পেছনে
─► App Tier: তোমার Code চালানো App Server Worker ┘ Scale Out
─► Cache (Redis) ও Database (Primary + Replica)
যে কথাগুলো জোরে বলা উচিত:
- Web ও App Tier Stateless রাখো (Session Redis বা Token-এ, File Object Storage-এ), যাতে Load Balancer-এর পেছনে ইচ্ছেমতো Machine যোগ বা বাদ দেওয়া যায়। এটাই Horizontal Scaling: আরও বড় একটি নয়, আরও কয়েকটি একই রকম App Server।
- প্রতি Box-এর Concurrency ঠিক করে App Server-এর Worker। মোটামুটি ক্ষমতার হিসাব: Worker × Machine ÷ গড় Request-এর সময়; প্রতিটি ১০০ মিলিসেকেন্ড নিলে ৮টি Worker প্রতি Machine-এ সেকেন্ডে প্রায় ৮০টি Request সামলায়। Request বেশিরভাগ সময় I/O-র অপেক্ষায় থাকলে Async Server বা বেশি Thread এই সংখ্যা বাড়ায়; CPU খাটলে শুধু বেশি Core-ই সাহায্য করে।
- App-এর যা দেখা উচিত না, সামনের স্তর তা শুষে নেয়: ধীর Client, TLS, Static File, অপব্যবহারকারী Traffic। এজন্যই Web Tier-এ App Tier-এর চেয়ে অনেক কম Machine লাগে।
- Single Point of Failure সরাও: অন্তত দুটি Load Balancer Node (বা একাধিক Zone জুড়ে একটি Managed), অন্তত দুটি App Server, আসল Dependency যাচাই করা Health Check, আর Graceful Shutdown, যাতে Deploy Connection কেটে না দিয়ে শেষ করতে দেয়।
- Deploy: Rolling (একবারে কয়েকটি Instance বদলানো), Blue-green (Load Balancer-কে নতুন একটি বহরে ঘুরিয়ে দেওয়া) বা Canary (আগে নতুন Version-কে ছোট একটি Weight দেওয়া)। সবই নির্ভর করে তোমার Configure করা Load Balancer ও Health Check-এর ওপর।
#নিজে করে দেখো
Docker-এ Nginx চালাও এবং তার Response Header দেখো:
docker run --rm -d --name web -p 8080:80 nginx
curl -I http://localhost:8080
# HTTP/1.1 200 OK
# Server: nginx/1.x.y <- Default-ভাবে Version ফাঁস হয়
# Content-Type: text/html
docker exec web nginx -T | head -40 # সম্পূর্ণ সক্রিয় Config দেখাও
docker logs -f web # Image-এ Access Log stdout-এ যায়
একটি ন্যূনতম Config যা একটি Folder পাঠায় আর /api/ Port 3000-এর একটি App-এ Proxy করে:
# site.conf
server {
listen 80;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ =404;
}
location /api/ {
proxy_pass http://host.docker.internal:3000; # Host Machine (Linux: --add-host=host.docker.internal:host-gateway যোগ করো)
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
docker run --rm -d --name web2 -p 8081:80 \
-v "$PWD/site.conf:/etc/nginx/conf.d/default.conf:ro" nginx
docker exec web2 nginx -t # Config Test
docker exec web2 nginx -s reload # site.conf বদলানোর পর Graceful Reload
Caddy দিয়ে একই Reverse Proxy, HTTPS-সহ (localhost-এর জন্য Caddy নিজের Local Certificate Authority ব্যবহার করে):
localhost {
reverse_proxy :3000
}
caddy run # Caddyfile যে Folder-এ আছে সেখানে
Production পদ্ধতিতে একটি Python App চালাও:
pip install gunicorn uvicorn
gunicorn -w 4 -b 127.0.0.1:8000 app:app # WSGI (Flask/Django), ৪টি Worker Process
uvicorn main:app --workers 4 --port 8000 # ASGI (FastAPI)
একটি দ্রুত Load Test, তারপর Static File আর Dynamic Endpoint তুলনা করো:
hey -n 5000 -c 100 http://localhost:8080/ # Nginx থেকে Static File
hey -n 5000 -c 100 http://localhost:8081/api/items # তোমার App-এ Proxy করা
ab -n 5000 -c 100 http://localhost:8080/ # ApacheBench দিয়ে একই কাজ
সেকেন্ডে কতগুলো Request আর Latency-র Percentile তুলনা করো: Static File সাধারণত অনেক দ্রুত, আর সেই পার্থক্যটাই তোমার Code চালানোর খরচ। আসল Server-এ Test চলার সময় Log দেখো:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn # Status Code (Default "combined" Format)
#সারসংক্ষেপ
মূল কথাগুলো
- Web Server HTTP-তে কথা বলে: গ্রহণ (ও TLS), পার্স, সিদ্ধান্ত (File, App, Redirect, প্রত্যাখ্যান), Response, Log। Static File সে নিজেই পাঠায়, Dynamic Request পাঠায় এমন একটি Application Server-এ যা তোমার Code চালায়। Reverse Proxy ও Load Balancer হলো ভূমিকা, যা প্রায়ই একই Software পালন করে।
- Apache: Virtual Host,
DirectoryRule, Module, আর.htaccess(Shared Hosting-এ সুবিধাজনক, প্রতিটি Request-এ পড়া হয় বলে ধীর)। এর MPM Concurrency ঠিক করে: prefork (প্রতি Connection-এ Process,mod_php-এর জন্য দরকার), worker (Thread), event (Thread, সঙ্গে অলস Keep-alive-এর জন্য একটি Listener)। - Nginx: root Master Port Bind করে এবং অধিকারহীন Worker সামলায়, প্রতি Core-এ একটি, প্রত্যেকে হাজার হাজার Non-blocking Connection-এর ওপর একটি Event Loop, তাই Memory প্রায় স্থির। Config হলো
http→server→location(Exact,^~, ক্রমানুসারে Regex, সবচেয়ে লম্বা Prefix), সঙ্গেtry_files,proxy_pass,upstream,proxy_cache,limit_req।nginx -tতারপরnginx -s reloadএকটি Connection-ও না ফেলে Worker বদলায়। - Caddy ACME দিয়ে নিজেই Certificate আনে ও নবায়ন করে (HTTP-01-এর জন্য DNS তার দিকে আর Port 80 খোলা থাকতে হয়)। Windows ও ASP.NET-এর জন্য IIS,
.htaccess-সামঞ্জস্যপূর্ণ Apache-বিকল্প হিসেবে LiteSpeed; অন্য ভূমিকাগুলো নেয় HAProxy, Envoy, Traefik, Varnish ও Cloud Load Balancer। - App Server-এর Interface: CGI (প্রতি Request-এ Process) → FastCGI / PHP-FPM (Pool,
pm.max_children), WSGI (Gunicorn) ও ASGI (Uvicorn), Rack (Puma), Servlet (Tomcat, প্রায়ই Spring Boot-এ Embed করা), Kestrel; Node.js ও Go App নিজেরাই Server। - Code কে তৈরি করেছে দেখে Debug করো: 502 (Upstream বন্ধ/প্রত্যাখ্যাত/Crash), 504 (Upstream খুব ধীর), 499 (Client হাল ছেড়েছে), 503 (সুস্থ Backend নেই, Maintenance বা Rate Limit), 413 (
client_max_body_size), 403 (Permission/Index), Redirect Loop (X-Forwarded-Proto)। Error Log কারণ বলে দেয়; Timeout বাইরে থেকে ভেতরে স্তরে স্তরে সাজাতে হয়। - System Design-এ: CDN → Load Balancer → Stateless Web Tier → Stateless App Tier → Cache ও Database, Horizontal-ভাবে Scale করা, Health Check ও Graceful Deploy-সহ।
আগে নিজে উত্তর দাও, তারপর ব্যাখ্যাটা পড়ো। ঠিক হলেও পড়ো, কারণ ভুল Option-গুলো কেন ভুল, সেটাও ওখানে আছে।
নিজেকে যাচাই করোপ্রশ্ন
একটা Web Server প্রতিটা Request পাঁচটা ধাপে সামলায়। কোন ধাপে সে ঠিক করে File পাঠাবে, Application-এর হাতে দেবে, Redirect করবে, নাকি ফিরিয়ে দেবে?
নিজেকে যাচাই করোপ্রশ্ন
নিচের কোনটা Dynamic Content?
নিজেকে যাচাই করোপ্রশ্ন
Nginx-এর Master Process Root হিসেবে চলে কেন?
নিজেকে যাচাই করোপ্রশ্ন
CGI ধীর ছিল কেন?
নিজেকে যাচাই করোপ্রশ্ন
কোন Interface-এ একটা Python Worker I/O-র অপেক্ষায় থাকা হাজার হাজার Request একসাথে সামলাতে পারে, আর WebSocket-ও সমর্থন করে?
নিজেকে যাচাই করোপ্রশ্ন
Caddy-র সবচেয়ে পরিচিত বৈশিষ্ট্য কোনটা?
নিজেকে যাচাই করোপ্রশ্ন
কোন Proxy xDS API দিয়ে চলন্ত অবস্থাতেই Configuration বদলাতে পারে, আর Istio Service Mesh-এ প্রতিটা Service-এর পাশে Sidecar হিসেবে চলে?
নিজেকে যাচাই করোপ্রশ্ন
কোন Tool Container চালু-বন্ধ হওয়ার সাথে সাথে Docker Label বা Kubernetes Resource দেখে নিজেই Route বানিয়ে নেয়?
নিজেকে যাচাই করোপ্রশ্ন
prefork MPM-ওয়ালা Apache-এর চেয়ে Nginx কেন অনেক কম Memory-তে ১০,০০০ অলস Keep-alive Connection সামলায়?
নিজেকে যাচাই করোপ্রশ্ন
একটা Django App চলছে --timeout 30 দেওয়া Gunicorn-এ, সামনে proxy_read_timeout 60s দেওয়া Nginx। একটা Report বানাতে লাগে ৪৫ সেকেন্ড। ব্যবহারকারী কী দেখবে?
নিজেকে যাচাই করোপ্রশ্ন
প্রতিটা Machine-এ ৮টা App Worker চলে, আর গড়ে একটা Request-এ লাগে ১০০ ms। Lesson-এর হিসাব ধরলে এমন ৫টা Machine প্রতি সেকেন্ডে মোটামুটি কয়টা Request সামলাতে পারবে?
নিজেকে যাচাই করোপ্রশ্ন
Nginx-এ ৪টা Worker, worker_connections 1024, আর প্রতিটা Request একটা App-এ Proxy হয়। তাত্ত্বিকভাবে একসাথে মোটামুটি কতজন Client সামলানো যাবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা Gunicorn Server চলছে ৪ Core-এর Machine-এ। Lesson-এর চেনা শুরুর নিয়ম ধরলে কয়টা Worker Process দিয়ে শুরু করবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা Server-এ প্রায় ৪,০০০ MB খালি RAM আছে, আর একটা PHP-FPM Process খায় প্রায় ৮০ MB। Lesson-এর নিয়ম মানলে pm.max_children কত হওয়া উচিত?
নিজেকে যাচাই করোপ্রশ্ন
Caddy ৯০ দিনের একটা Let’s Encrypt Certificate পেল, আর মেয়াদের মোটামুটি এক-তৃতীয়াংশ বাকি থাকলে নবায়ন করে। পাওয়ার কত দিন পরে সে নবায়ন করবে?
নিজেকে যাচাই করোপ্রশ্ন
Nginx /api/report-এর জন্য অনেকগুলো 499 লিখছে। সামনে একটা Cloud Load Balancer, যার Idle Timeout ৩০ সেকেন্ড; Nginx-এর proxy_read_timeout ৬০ সেকেন্ড। কী ঘটছে?
নিজেকে যাচাই করোপ্রশ্ন
৫০ MB-এর Video Upload করতে গেলে ব্যবহারকারীরা 413 পাচ্ছে, ছোট Upload ঠিকই চলছে। Nginx ডিফল্ট Setting-এ চলছে। ঠিক সমাধান কী?
নিজেকে যাচাই করোপ্রশ্ন
Nginx /img/logo.png-এর জন্য 403 দিচ্ছে। File আছে, কিন্তু তার ওপরের Folder-টা Root বানিয়েছে, অন্য User-দের কোনো Permission নেই। সমস্যা কোথায়?
নিজেকে যাচাই করোপ্রশ্ন
একটা Nginx Server-এ আছে location /static/ { root /var/www/assets; }। Browser চাইল /static/app.css। Nginx কোন File খুলতে চেষ্টা করবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা Load Balancer TLS শেষ করে App-এর সাথে সাধারণ HTTP-তে কথা বলে, আর Browser ‘অনেক বেশি Redirect’ Error দিয়ে থেমে যাচ্ছে। সাধারণত কারণটা কী?
নিজেকে যাচাই করোপ্রশ্ন
তুমি nginx.conf বদলালে, একটা টাইপো রয়ে গেল, তারপর nginx -s reload চালালে। কী হবে?
নিজেকে যাচাই করোপ্রশ্ন
Open-source Nginx-এর একটা upstream Block-এর তিনটা Server-ই ব্যর্থ বলে চিহ্নিত। Client কী পাবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা Access Log লাইনের শেষে আছে rt=12.4 urt=0.05। এ থেকে কী বোঝা যায়?
নিজেকে যাচাই করোপ্রশ্ন
Nginx-এর limit_req বাড়তি লগইন চেষ্টা ফিরিয়ে দিচ্ছে, আর তোমার Monitoring প্রতিটা 503-কে Outage ধরে নিচ্ছে। সহজ সমাধান কী?
নিজেকে যাচাই করোপ্রশ্ন
Nginx-এ আছে location ^~ /assets/, আর পরে location ~* \.css$। /assets/site.css কে সামলাবে?
নিজেকে যাচাই করোপ্রশ্ন
Notes-এ Apache-কে বলা হয়েছে ‘a patchy server’। নামটা নিয়ে Lesson কী বলে?
নিজেকে যাচাই করোপ্রশ্ন
বাইরের ধাপ থেকে ভেতরের ধাপ পর্যন্ত Timeout-গুলোর কোন ক্রমটা সঠিক?
নিজেকে যাচাই করোপ্রশ্ন
.htaccess চালু থাকলে Apache ধীর হয়ে যায় কেন?
নিজেকে যাচাই করোপ্রশ্ন
কোন দুটো Setting সরাসরি Slowloris আক্রমণ ঠেকায়? (দুটো বেছে নাও।)
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
Gunicorn, Puma আর Node সবাই সরাসরি Browser-কে উত্তর দিতে পারে। তবুও সামনে Nginx রাখার সত্যিকারের দুটো কারণ কী? (দুটো বেছে নাও।)
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
Open-source Nginx-এর Load Balancing নিয়ে কোন দুটো কথা সত্য? (দুটো বেছে নাও।)
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
Nginx-এর Graceful Reload নিয়ে কোন দুটো কথা সত্য? (দুটো বেছে নাও।)
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
System Design Interview-তে তুমি আঁকলে CDN → Load Balancer → Web Tier → App Tier → Cache ও Database। কোন দুটো সিদ্ধান্ত App Tier-কে পরিষ্কারভাবে Scale Out করতে দেয় আর Single Point of Failure দূর করে? (দুটো বেছে নাও।)
বেছে নাও ২