NGINX Unit 作為一個多功能應用程式伺服器,支援多種程式語言和框架,簡化了應用程式佈署流程。本文除了 Django 和 Express 之外,也以 WordPress 為例,說明如何使用 NGINX Unit 佈署 PHP 應用程式,包含設定資料函式庫、組態 PHP 應用程式物件、設定檔案許可權以及使用 NGINX 提供靜態內容和反向代理等步驟。針對 Django 和 Express,文章詳細說明瞭如何設定專案、組態 NGINX Unit 的 JSON 設定檔,以及如何提交組態並驗證應用程式是否正常運作。此外,文章也涵蓋瞭如何設定 NGINX 作為反向代理,將 NGINX Unit 應用程式暴露給外部,以及如何使用 upstream 模組進行負載平衡的設定。

應用程式整合

簡介

本章將透過逐步設定常見的應用程式框架,展示如何使用 NGINX Unit 服務真實世界的應用程式。在本章中,您將學習如何服務 WordPress(一種常見的 PHP 內容管理系統),以及如何服務根據 Django(Python 框架)和 Express(Node.js 框架)等常見框架的應用程式。本章將示範如何在系統上安裝應用程式,並確保它們具有正確的檔案許可權和 NGINX Unit 的組態,以提供服務。

WordPress

問題

您需要使用 NGINX Unit 執行 WordPress。

解決方案

要安裝 WordPress,如果尚未安裝,請檢查先決條件以確保滿足必要條件。接下來,組態 WordPress 資料函式庫。然後下載並解壓縮 WordPress 檔案:

sudo mkdir /var/app/
sudo cd /var/app/
sudo wget https://wordpress.org/latest.tar.gz
sudo tar xzvf latest.tar.gz

在此範例中,WordPress 檔案將儲存在 /var/app/wordpress/ 中。

更新 wp-config.php 檔案中的資料函式庫設定和其他自定義內容。 設定 WordPress 的使用者檔案許可權,以確保擁有 PHP 程式和 NGINX 網頁伺服器的使用者能夠存取檔案:

sudo chown -R wpuser:www-data /var/app/wordpress/
sudo find /var/app/wordpress/ -type d -exec chmod g+s {} \;
sudo chmod g+w /var/app/wordpress/wp-content
sudo chmod -R g+w /var/app/wordpress/wp-content/themes
sudo chmod -R g+w /var/app/wordpress/wp-content/plugins

組態 PHP 應用程式物件以及監聽器物件,並將兩個物件提交給 NGINX Unit 控制介面。本範例將組態兩個應用程式和監聽器,以隔離主要的 WordPress 入口點 index.php 與其他可以執行的 PHP 檔案(如 wp-admin.php)。將以下 JSON 檔案命名為 wordpress-unit.json

{
  "listeners": {
    "127.0.0.1:8090": {
      "pass": "applications/wp_index"
    },
    "127.0.0.1:8091": {
      "pass": "applications/wp_direct"
    }
  },
  "applications": {
    "wp_index": {
      "type": "php",
      "user": "wpuser",
      "group": "www-data",
      "root": "/var/app/wordpress/",
      "script": "index.php"
    },
    "wp_direct": {
      "type": "php",
      "user": "wpuser",
      "group": "www-data",
      "root": "/var/app/wordpress/",
      "index": "index.php"
    }
  }
}

wordpress-unit.json 檔案提交給 Unit 控制介面:

sudo curl -X PUT -d @wordpress-unit.json \
--unix-socket /var/run/control.unit.socket \
http://localhost/config

組態 NGINX 以提供靜態內容並將請求代理到剛剛在 NGINX Unit 中組態的應用程式,使用以下基本 upstream 和 server 組態:

upstream unit_wp_index {
  server 127.0.0.1:8090;
}

upstream unit_wp_direct {
  server 127.0.0.1:8091;
}

server {
  listen 80;
  server_name localhost;
  root /var/app/wordpress/;

  location / {
    try_files $uri @index_php;
  }

  location @index_php {
    proxy_pass http://unit_wp_index;
    proxy_set_header Host $host;
  }

  location /wp-admin {
    index index.php;
  }

  location ~* \.php$ {
    try_files $uri =404;
    proxy_pass http://unit_wp_direct;
    proxy_set_header Host $host;
  }
}

使用瀏覽器向 NGINX 伺服器的埠 80 發出請求,並完成安裝過程。

詳細分析

在此配方中,從頭開始安裝 WordPress。首先需要根據 WordPress 的規格準備系統和資料函式庫。在準備好系統後,將程式碼函式庫下載並解壓縮到檔案系統上的某個位置。

一旦應用程式碼位於檔案系統上,就需要告知 WordPress 如何連線到資料函式庫。這是透過更改程式碼函式庫中包含的組態檔案來完成的。為了簡潔起見,這是靜態組態的。在生產系統中,將使用環境變數並在組態 Unit 應用程式時設定。

在組態了資料函式庫連線後,更改檔案許可權,以便擁有 Unit 程式的系統使用者能夠讀取檔案。同時為系統群組設定許可權,該群組將被 NGINX 程式用於提供靜態內容。

在組態 Unit 以提供應用程式時,會採取安全措施隔離主要的 WordPress 入口點與直接的 PHP 檔案。兩個組態的應用程式之間的主要區別在於 script 和 index 設定。當使用 script 應用程式屬性時,Unit 將執行它收到的任何 URL,例如 /wp-login.php。當使用 index 屬性時,只有作為值提供的檔案將被執行。這種分離允許根據預期的用法改變應用程式設定。一個有用的例子是限制存取或允許 WordPress 管理部分的更長的請求超時。

Unit 不提供靜態內容,其中 WordPress 有很多。為了提供此內容,需要 NGINX 網頁伺服器。為了提供靜態和動態內容的單一端點,NGINX 也被組態為代理到應用程式。所提供的組態在埠 80 上託管一個網頁伺服器。當向網頁伺服器發出請求時,NGINX 將檢查檔案系統上是否有與 URL 相匹配的靜態檔案。如果找不到該檔案,則請求被代理到 wp-index Unit 監聽器(除非 URL 以 .php 結尾,在這種情況下,請求將被代理到 wp-direct Unit 監聽器)。

Django

問題

您有一個 Python Django 應用程式,想要使用 NGINX Unit 提供服務。

解決方案

準備您現有的專案或建立一個新的專案。在本範例中,原始碼將放置在 /var/project/ 中。首先確保設定了正確的檔案許可權:

sudo chown -R app-user:app-user /var/project/

詳細說明範例的目錄結構很重要,因為 Unit 需要知道如何匯入 WSGI 模組才能執行應用程式。因此,Unit 應用程式物件值取決於目錄結構:

/var/project/
├── manage.py
├── app1/
 └── ...
├── app2/
 └── ...
└── project/
    ├── ...
    └── wsgi.py

建構一個 NGINX Unit Python 應用程式物件和相關聯的監聽器。將此檔案命名為 django-unit.json

{
  "listeners": {
    "127.0.0.1:8080": {
      "pass": "applications/django_project"
    }
  },
  "applications": {
    "django_project": {
      "type": "python",
      "path": "/var/project/",
      "home": "/path/to/virtual-env/if/used/",
      # 其他必要的設定...
    }
  }
}

詳細分析與程式碼解密

此 JSON 組態檔案的重點在於設定一個名為 django_project 的 Python 型別應用程式,並指定其路徑和虛擬環境(如果有的話)。監聽器設定為將請求轉發到這個應用程式。

{
  # 設定監聽器,接收來自特定IP和埠的請求
  "listeners": {
    "127.0.0.1:8080": {
      # 將請求轉發到名為 django_project 的應用程式
      "pass": "applications/django_project"
    }
  },
  
  # 定義應用程式的具體組態
  "applications": {
    "django_project": {
      # 指定應用程式的型別為 Python
      "type": "python",
      
      # 指定專案路徑,Unit 需要知道從哪裡匯入 WSGI 模組
      "path": "/var/project/",
      
      # 如果使用虛擬環境,需要指定虛擬環境路徑
      "home": "/path/to/virtual-env/if/used/",
      
      # 其他必要的設定,如 module 或其他引數...
    }
  }
}
程式碼作用與邏輯
  1. 監聽器設定:此部分定義了 NGINX Unit 的監聽行為,即從哪裡接收請求並將其轉發到指定的應用程式。

    • IP 地址 127.0.0.1 表示本地主機。
    • 連線埠 8080 是此監聽器使用的特定埠。
    • "pass" 指標明瞭請求應該被轉發到的目標,在這裡是名為 django_project 的應用程式。
  2. 應用程式設定:這部分詳細定義了名為 django_project 的 Python 型別應用程式。

    • "type" 指定了應用程式型別,這裡是 Python,表示此應用是一個 Python WSGI 應用。
    • "path" 設定了專案的根路徑,這是 Unit 用來找到 WSGI 模組的位置。
    • "home" 設定了虛擬環境(如果使用)的路徑,這對於隔離和管理 Python 環境十分重要。
  3. WSGI 模組匯入:Unit 使用指定的 pathhome 環境來匯入 WSGI 模組,使其能夠執行 Django 應用。

注意事項與潛在改進
  • 確保指定的路徑和虛擬環境路徑正確無誤,以避免匯入錯誤或執行失敗。
  • 在生產環境中,應考慮安全性和效能最佳化,例如適當組態防火牆規則或最佳化 WSGI 設定。
  • 虛擬環境的使用可以幫助隔離專案依賴,提高可移植性和可維護性。

圖表翻譯與分析

以下 Mermaid 圖表展示了 NGINX Unit 如何與 Django 應用互動:

  graph LR;
    A[客戶端] -->|HTTP 請求| B[NGINX];
    B -->|轉發請求| C[NGINX Unit];
    C -->|處理請求| D[Django 應用];
    D -->|傳回回應| C;
    C -->|傳回回應| B;
    B -->|傳回回應| A;

圖表翻譯:此圖表描述了客戶端請求如何經過 NGINX、NGINX Unit 最終到達 Django 應用,並傳回回應給客戶端的過程。每一步驟代表了一個處理環節,最終完成了客戶端與伺服器之間的互動。

詳細解釋
  1. 客戶端發起請求:客戶端(如瀏覽器)向伺服器發起 HTTP 請求。
  2. NGINX 處理請求:NGINX 首先接收到請求,它可以根據組態進行初步處理,如靜態檔案服務或反向代理。
  3. 轉發請求至 NGINX Unit:NGINX 將動態請求轉發給 NGINX Unit,後者負責處理 Python 應用。
  4. NGINX Unit 處理請求:NGINX Unit 負責載入並執行 Python 應用,如 Django 專案,處理業務邏輯。
  5. Django 應用處理業務邏輯:Django 作為 Web 應用框架,處理具體的業務邏輯,如資料函式庫操作、範本渲染等。
  6. 傳回回應:處理完成後,Django 傳回回應給 NGINX Unit。
  7. 回應傳回客戶端:最終,NGINX Unit 將回應傳回給 NGINX,再由 NGINX 傳回給客戶端,完成整個請求處理流程。

這個流程展示了現代 Web 應用架構中常見的分層設計和元件之間的協同工作。

透過NGINX Unit佈署Django與Express應用程式

本篇文章將深入探討如何使用NGINX Unit來佈署Django和Express應用程式。NGINX Unit是一個多功能的應用程式伺服器,能夠支援多種程式語言和框架。

使用NGINX Unit佈署Django應用程式

步驟一:設定Django專案

首先,需要設定Django專案並確保其正確運作。以下是一個基本的Django專案結構:

/var/app/
    django_project/
        manage.py
        django_project/
            __init__.py
            settings.py
            urls.py
            wsgi.py

步驟二:組態NGINX Unit

接下來,需要建立一個JSON檔案來組態NGINX Unit。以下是一個範例組態:

{
    "listeners": {
        "127.0.0.1:8080": {
            "pass": "applications/django_project"
        }
    },
    "applications": {
        "django_project": {
            "type": "python",
            "path": "/var/app/django_project/",
            "module": "django_project.wsgi",
            "user": "app-user"
        }
    }
}

#### 內容解密:

此組態定義了一個名為django_project的應用程式,使用Python語言,並指定了WSGI模組的位置。同時,定義了一個監聽器,將來自127.0.0.1:8080的請求轉發給django_project應用程式。

步驟三:提交組態到NGINX Unit

使用以下命令將組態提交到NGINX Unit:

sudo curl -X PUT -d @django-unit.json \
--unix-socket /var/run/control.unit.socket \
http://localhost/config

#### 內容解密:

此命令透過Unix通訊端將組態提交到NGINX Unit的控制介面,從而更新其組態。

步驟四:驗證應用程式

最後,透過造訪http://localhost:8080來驗證Django應用程式是否正確運作。

使用NGINX Unit佈署Express應用程式

步驟一:安裝必要的套件

首先,需要安裝unit-http套件,該套件提供了與NGINX Unit相容的HTTP伺服器物件。

npm install unit-http

#### 內容解密:

unit-http套件是Express應用程式與NGINX Unit整合所需的關鍵套件,它提供了相容的HTTP伺服器物件。

步驟二:修改Express應用程式

接下來,需要修改Express應用程式以使用unit-http套件提供的物件。以下是一個範例:

#!/usr/bin/env node
const {
    createServer,
    IncomingMessage,
    ServerResponse,
} = require('unit-http')
require('http').ServerResponse = ServerResponse
require('http').IncomingMessage = IncomingMessage
const express = require('express')
const app = express()
app.get('/', (req, res) => {
    res.set('X-Header-Example', 'Value')
    res.send('Hello, Unit!')
})
createServer(app).listen()

#### 內容解密:

此範例展示瞭如何修改Express應用程式以使用unit-http套件。它取代了預設的HTTP伺服器物件,並建立了一個與NGINX Unit相容的伺服器。

步驟三:組態NGINX Unit

建立一個JSON檔案來組態NGINX Unit,以下是一個範例組態:

{
    "listeners": {
        "127.0.0.1:8080": {
            "pass": "applications/express_project"
        }
    },
    "applications": {
        "express_project": {
            "type": "external",
            "executable": "/var/app/index.js",
            "user": "app-user"
        }
    }
}

#### 內容解密:

此組態定義了一個名為express_project的外部應用程式,指定了可執行檔案的位置和執行使用者。同時,定義了一個監聽器,將來自127.0.0.1:8080的請求轉發給express_project應用程式。

透過NGINX反向代理到NGINX Unit應用程式

設定NGINX反向代理

為了將NGINX Unit應用程式暴露給外部,需要設定NGINX作為反向代理。以下是一個範例組態:

upstream unit_backend {
    server 127.0.0.1:8080; # 本地反向代理
    server 10.0.0.12:8080; # 遠端伺服器負載平衡
    server 10.0.1.12:8080; # 遠端伺服器負載平衡
}

#### 圖表翻譯:

此圖示展示了NGINX作為反向代理,將請求轉發給後端的NGINX Unit伺服器。

  graph LR;
    A[客戶端] -->|請求| B[NGINX反向代理];
    B -->|轉發| C[NGINX Unit];
    C -->|處理| D[Django/Express應用程式];

此圖表說明瞭客戶端請求如何透過NGINX反向代理轉發到後端的NGINX Unit伺服器,並最終由Django或Express應用程式處理。