عنوان:

‫ NGINX برای توسعه‌دهندگان ASP.NET Core - قسمت ششم - پروژه عملی و جمع‌بندی


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۰۱ ۰۸:۱۰
آدرس: www.dntips.ir
در این بخش، تمام دانش و مهارت‌هایی را که در طول دوره کسب کرده‌ایم، در قالب یک پروژه جامع و عملی به کار می‌گیریم. سپس با مرور نکات کلیدی، یادگیری خود را تثبیت می‌کنیم.

بخش ۶: پروژه عملی و جمع‌بندی
هدف این بخش، شبیه‌سازی کامل یک سناریوی استقرار در دنیای واقعی است. شما یک اپلیکیشن ASP.NET Core را از ابتدا تا انتها برای محیط Production آماده خواهید کرد. این پروژه بهترین راه برای سنجش مهارت‌های شما و ایجاد اعتماد به نفس برای پروژه‌های آینده است.

۱. پروژه پایانی: استقرار کامل یک اپلیکیشن حرفه‌ای
شرح پروژه: شما باید یک اپلیکیشن نمونه ASP.NET Core MVC که دارای بخش عمومی و یک بخش ادمین (نیازمند لاگین) است را به صورت امن، بهینه و با دسترس‌پذیری بالا (High Availability) روی سرور لینوکس و با استفاده از NGINX مستقر کنید.

چک‌لیست مراحل پروژه:
۱. آماده‌سازی اپلیکیشن:
  • یک اپلیکیشن جدید ASP.NET Core MVC با قابلیت احراز هویت بسازید: dotnet new mvc --auth Individual.
  • اپلیکیشن را در حالت Release پابلیش کنید.
  • فایل‌های پابلیش شده را به مسیر /var/www/final-project در سرور خود منتقل کنید.

۲. راه‌اندازی سرویس پشتیبان (با دسترس‌پذیری بالا):
  • دو فایل سرویس systemd مجزا بسازید (kestrel-fp-5000.service و kestrel-fp-5001.service).
  • هر سرویس باید یک نمونه از اپلیکیشن را به ترتیب روی پورت‌های 5000 و 5001 اجرا کند.
  • اطمینان حاصل کنید که هر دو سرویس به صورت خودکار پس از بوت شدن سرور اجرا می‌شوند.

۳. پیکربندی اصلی NGINX:
  • یک فایل کانفیگ جدید به نام final-project.conf در sites-available ایجاد کنید.
  • یک بلوک upstream به نام project_backend تعریف کنید که شامل هر دو نمونه اپلیکیشن (پورت‌های 5000 و 5001) باشد. از الگوریتم توزیع بار least_conn استفاده کنید.
  • بلوک server اصلی را طوری تنظیم کنید که به درخواست‌های دامنه‌ی شما (مثلاً final-project.your-domain.com) گوش دهد.

۴. امنیت (HTTPS و هدرها):
  • با استفاده از certbot، یک گواهینامه SSL رایگان از Let's Encrypt برای دامنه خود دریافت و نصب کنید.
  • مطمئن شوید که تمام ترافیک HTTP به صورت خودکار به HTTPS ریدایرکت می‌شود.
  • مجموعه کامل هدرهای امنیتی (HSTS, X-Frame-Options, X-Content-Type-Options و یک CSP پایه) را به کانفیگ خود اضافه کنید.

۵. بهینه‌سازی عملکرد:
  • NGINX را طوری تنظیم کنید که فایل‌های استاتیک را مستقیماً از پوشه wwwroot پروژه سرو کند (با استفاده از متد try_files).
  • فشرده‌سازی Gzip را برای فایل‌های متنی فعال کنید.
  • (چالش امتیازی): برای یک صفحه عمومی و غیرحساس (مانند صفحه اصلی)، کش پراکسی را با زمان انقضای ۵ دقیقه فعال کنید.

۶. تنظیمات پیشرفته (محدودسازی نرخ):
  • یک ناحیه محدودسازی نرخ (Rate Limit Zone) تعریف کنید.
  • یک محدودیت معقول (مثلاً ۱۰ درخواست در دقیقه) روی صفحه لاگین اپلیکیشن (/Identity/Account/Login) اعمال کنید تا از حملات Brute-force جلوگیری شود.

۷. تأیید نهایی:
  • صحت فایل کانفیگ NGINX را با nginx -t بررسی کنید.
  • سرویس NGINX را reload کنید.
  • با مرورگر خود به آدرس https://final-project.your-domain.com بروید و از صحت عملکرد سایت مطمئن شوید.
  • با ابزارهای توسعه‌دهنده مرورگر (DevTools)، وجود هدرهای امنیتی، Content-Encoding: gzip و وضعیت کش را بررسی کنید.
  • با متوقف کردن یکی از سرویس‌های systemd، تست کنید که سایت همچنان در دسترس باقی می‌ماند (تست Load Balancing).

۲. مرور نکات کلیدی و بهترین رویه‌ها (Best Practices)
این لیست، یک "تقلب‌نامه" مفید از مهم‌ترین نکاتی است که در این دوره آموختید.
  • چرا NGINX؟ همیشه در محیط Production از یک Reverse Proxy مانند NGINX در جلوی Kestrel استفاده کنید. Kestrel یک اپلیکیشن سرور است، نه یک وب سرور امن و کامل برای قرار گرفتن در لبه شبکه.
  • مدیریت کانفیگ: از ساختار sites-available و sites-enabled استفاده کنید. همیشه قبل از reload، کانفیگ خود را با nginx -t تست کنید. برای اعمال تغییرات بدون قطعی، از reload استفاده کنید نه restart.
  • امنیت در اولویت: HTTPS اجباری است. از certbot برای سهولت کار استفاده کنید. هدرهای امنیتی را برای مقابله با حملات سمت کلاینت فراموش نکنید. روی نقاط حساس مانند صفحه لاگین، محدودیت نرخ اعمال کنید. سرویس اپلیکیشن خود را با یک کاربر غیر-root (مانند www-data) اجرا کنید.
  • عملکرد کلیدی است: اجازه دهید NGINX فایل‌های استاتیک شما را سرو کند. فشرده‌سازی Gzip/Brotli را فعال کنید. برای مقیاس‌پذیری و پایداری از Load Balancing استفاده کنید. برای داده‌های عمومی و پرکاربرد، از Caching بهره ببرید.
  • جریان کار استقرار: اپلیکیشن خود را در حالت Release پابلیش کنید. فرآیند اجرای آن را با systemd مدیریت کنید تا به صورت خودکار اجرا شود. برای استقرارهای مدرن، استفاده از Docker و Docker Compose را در نظر بگیرید.
  • عیب‌یابی: خطای 502 Bad Gateway تقریباً همیشه به این معنی است که اپلیکیشن ASP.NET Core شما اجرا نشده یا NGINX نمی‌تواند به آن دسترسی پیدا کند. لاگ‌های NGINX (/var/log/nginx/error.log) و لاگ‌های اپلیکیشن (journalctl -fu your-service-name) بهترین دوستان شما برای یافتن مشکل هستند.

۳. پرسش و پاسخ و گام‌های بعدی
محتوای رسمی این دوره در اینجا به پایان می‌رسد. شما اکنون یک دید جامع و مهارت عملی برای استقرار حرفه‌ای اپلیکیشن‌های ASP.NET Core در دنیای واقعی را دارید. دنیای NGINX بسیار وسیع است و این دوره یک نقطه شروع قدرتمند برای شما بود.

موضوعات پیشنهادی برای مطالعه بیشتر:
  • استفاده از ماژول‌های پیشرفته NGINX (مانند اسکریپت‌نویسی با Lua).
  • سفارشی‌سازی پیشرفته Content-Security-Policy.
  • استفاده از NGINX به عنوان یک API Gateway.
  • تنظیم دقیق پارامترهای عملکردی NGINX مانند worker_processes و worker_connections.

نظرات

  • وحید نصیری در ۱۴۰۴/۰۴/۰۱ ۱۰:۳۹
    در ادامه، فایل‌های نهایی پیکربندی برای دو سناریوی اصلی استقرار (استاندارد روی سرور مجازی و با استفاده از Docker) بر اساس چک‌لیست پروژه پایانی تهیه شده‌اند. این فایل‌ها شامل تمام مفاهیمی هستند که در دوره آموختیم.

    سناریوی اول: استقرار استاندارد روی سرور لینوکس
    در این سناریو، ما اپلیکیشن را با systemd به عنوان سرویس اجرا کرده و NGINX را مستقیماً روی سرور نصب و پیکربندی می‌کنیم.

    ۱. فایل سرویس systemd (برای نمونه اول)
    این فایل را در مسیر /etc/systemd/system/kestrel-final-project-5000.service ایجاد کنید.
    # /etc/systemd/system/kestrel-final-project-5000.service
    
    [Unit]
    Description=Final Project ASP.NET Core App running on Kestrel (Port 5000)
    
    [Service]
    # مسیر پوشه‌ای که فایل‌های پابلیش شده اپلیکیشن در آن قرار دارد
    WorkingDirectory=/var/www/final-project
    
    # دستور اصلی برای اجرای اپلیکیشن.
    # حتما نام فایل dll خود را جایگزین FinalProject.dll کنید.
    # با --urls به صورت صریح پورت اجرایی این نمونه را مشخص می‌کنیم.
    ExecStart=/usr/bin/dotnet /var/www/final-project/FinalProject.dll --urls "http://localhost:5000"
    
    # راه‌اندازی مجدد خودکار در صورت بروز خطا
    Restart=always
    # تاخیر ۱۰ ثانیه‌ای قبل از راه‌اندازی مجدد
    RestartSec=10
    KillSignal=SIGINT
    
    # اجرای سرویس با کاربر کم‌اختیار www-data برای افزایش امنیت
    User=www-data
    
    # تنظیم متغیرهای محیطی برای اپلیکیشن
    Environment=ASPNETCORE_ENVIRONMENT=Production
    Environment=DOTNET_PRINT_CONSOLE_OUTPUT=true
    
    [Install]
    WantedBy=multi-user.target
    نکته: برای ساخت سرویس دوم (نمونه‌ای که روی پورت 5001 اجرا می‌شود)، کافی است این فایل را با نام kestrel-final-project-5001.service کپی کرده و در خط ExecStart، پورت را به 5001 تغییر دهید.

    ۲. فایل پیکربندی سایت NGINX (final-project.conf)
    این فایل، قلب پروژه ماست و تمام قطعات را به هم متصل می‌کند. آن را در مسیر /etc/nginx/sites-available/final-project.conf ایجاد کنید.
    # /etc/nginx/sites-available/final-project.conf
    
    # ۱. تعریف گروه سرورهای پشتیبان برای توزیع بار (Load Balancing)
    upstream project_backend {
        # استفاده از الگوریتم "کمترین ارتباط فعال" برای توزیع هوشمندانه‌تر
        least_conn;
    
        # لیست نمونه‌های در حال اجرای اپلیکیشن
        server localhost:5000;
        server localhost:5001;
    }
    
    # نکته: این بخش باید در فایل اصلی nginx.conf و داخل بلوک http قرار گیرد.
    # limit_req_zone $binary_remote_addr zone=login_limit:10m rate=10r/m;
    
    
    # ۲. بلوک اصلی سرور که به درخواست‌های وبسایت پاسخ می‌دهد
    server {
        # گوش دادن روی پورت 80 و 443 (برای SSL)
        # http2 عملکرد بهتری ارائه می‌دهد
        listen 80;
        listen 443 ssl http2;
        server_name final-project.your-domain.com; # <-- دامنه خود را اینجا وارد کنید
    
        # ۳. تنظیمات SSL/TLS
        # این خطوط توسط certbot به صورت خودکار پر می‌شوند
        ssl_certificate /etc/letsencrypt/live/final-project.your-domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/final-project.your-domain.com/privkey.pem;
        # تنظیمات امنیتی پیشنهادی برای SSL
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
    
        # ۴. افزودن هدرهای امنیتی
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
        add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline';" always;
    
        # ۵. سرو کردن فایل‌های استاتیک
        # مسیر ریشه برای فایل‌های استاتیک (wwwroot)
        root /var/www/final-project/wwwroot;
    
        # قانون اصلی برای مدیریت درخواست‌ها
        location / {
            # ابتدا تلاش کن فایل استاتیک را پیدا کنی، اگر نبود به پراکسی بفرست
            try_files $uri @proxy;
        }
    
        # ۶. مکان‌یابی (Location) برای مسیرهای حساس
        # اعمال محدودیت نرخ روی صفحه لاگین
        location /Identity/Account/Login {
            limit_req zone=login_limit burst=10 nodelay;
            
            # پس از بررسی محدودیت، درخواست را به پراکسی ارسال کن
            proxy_pass http://project_backend;
            # افزودن هدرهای ضروری برای پراکسی
            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;
        }
    
        # ۷. مکان‌یابی اصلی برای Reverse Proxy
        location @proxy {
            # ارسال ترافیک به گروه سرورهای پشتیبان
            proxy_pass http://project_backend;
    
            # تنظیمات ضروری برای هدرها و پشتیبانی از WebSocket (برای SignalR)
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
            proxy_cache off; # کش برای ارتباطات WebSocket توصیه نمی‌شود
            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;
        }
    }
    
    # بلوک سرور برای ریدایرکت دائمی HTTP به HTTPS
    # این بلوک هم توسط certbot به صورت خودکار ایجاد می‌شود
    server {
        listen 80;
        server_name final-project.your-domain.com;
        return 301 https://$host$request_uri;
    }

    سناریوی دوم: استقرار با Docker (استفاده از Docker Compose)
    این یک روش مدرن و ایزوله برای استقرار است. تمام فایل‌های زیر باید در پوشه اصلی پروژه شما قرار داشته باشند.

    ۱. فایل Dockerfile برای اپلیکیشن ASP.NET Core
    این فایل را در پوشه پروژه ASP.NET Core خود قرار دهید.
    # Dockerfile
    
    # مرحله ۱: ساخت (Build) اپلیکیشن
    FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
    WORKDIR /src
    
    # کپی کردن فایل‌های پروژه و بازیابی پکیج‌ها
    COPY ["FinalProject.csproj", "."]
    RUN dotnet restore "./FinalProject.csproj"
    
    # کپی کردن بقیه سورس کد و پابلیش کردن پروژه
    COPY . .
    WORKDIR "/src/."
    RUN dotnet publish "FinalProject.csproj" -c Release -o /app/publish
    
    # مرحله ۲: ساخت ایمیج نهایی و بهینه
    FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
    WORKDIR /app
    COPY --from=build /app/publish .
    
    # پورت داخلی که Kestrel روی آن گوش می‌دهد
    EXPOSE 8080
    
    # دستور اجرای اپلیکیشن هنگام استارت شدن کانتینر
    ENTRYPOINT ["dotnet", "FinalProject.dll"]

    ۲. فایل پیکربندی NGINX برای Docker (default.conf)
    این فایل را در یک پوشه به نام nginx در کنار docker-compose.yml قرار دهید (./nginx/default.conf).
    # ./nginx/default.conf
    
    server {
        listen 80;
    
        location / {
            # نام "aspnet-app" نام سرویسی است که در docker-compose تعریف شده.
            # داکر به صورت خودکار این نام را به IP داخلی کانتینر اپلیکیشن ترجمه می‌کند.
            # پورت 8080 همان پورتی است که در Dockerfile اکسپوز کردیم.
            proxy_pass http://aspnet-app:8080;
            
            # تنظیمات استاندارد پراکسی
            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;
    
            # پشتیبانی از WebSocket
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }
    }

    ۳. فایل docker-compose.yml
    این فایل ارکستراتور اصلی است و دو سرویس ما را تعریف و به هم متصل می‌کند. آن را در ریشه پروژه قرار دهید.
    # docker-compose.yml
    
    version: '3.8'
    
    services:
      # سرویس اپلیکیشن ASP.NET Core
      aspnet-app:
        container_name: final-project-app
        # ساخت ایمیج از روی Dockerfile موجود در همین مسیر
        build:
          context: .
          dockerfile: Dockerfile
        restart: always
        environment:
          # تنظیم Kestrel برای گوش دادن روی پورت 8080 در تمام اینترفیس‌های شبکه داخل کانتینر
          - ASPNETCORE_URLS=http://+:8080
    
      # سرویس NGINX به عنوان Reverse Proxy
      nginx-proxy:
        container_name: final-project-nginx
        image: nginx:latest
        restart: always
        ports:
          # پورت 80 ماشین میزبان را به پورت 80 کانتینر NGINX متصل کن
          - "80:80"
          # در صورت نیاز به SSL، پورت 443 را هم متصل کنید
          - "443:443"
        volumes:
          # فایل کانفیگ محلی ما را در مسیر کانفیگ پیش‌فرض NGINX در کانتینر قرار بده
          - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
        # قبل از اجرای NGINX، منتظر باش تا سرویس اپلیکیشن آماده شود
        depends_on:
          - aspnet-app
    با این فایل‌ها، شما دو الگوی کامل و آماده برای استقرار پروژه‌های ASP.NET Core خود با استفاده از NGINX در اختیار دارید.