初學者指南:設定 Apache 反向代理 Django 服務(含 SSL)

更新日期: 2025 年 3 月 13 日

在使用 Django 開發網站時,通常會需要將其部署到伺服器,並透過 Apache 作為反向代理(Reverse Proxy)來轉發請求。

同時,為了確保網站的安全性,我們也會使用 SSL(HTTPS)。

本指南將詳細說明如何設定 Apache,使其能夠正確轉發 Django 服務的請求,並啟用 SSL 憑證。

本指南適合初學者,將逐步解析 Apache 設定檔案的內容,並教你如何獲取 DocumentRoot 目錄,以確保設定的正確性。


Apache 設定 Django 反向代理與 SSL

在 Apache 伺服器上,我們可以使用 VirtualHost 來設定網站的網域名稱、文件目錄、反向代理等功能。

以下是一個完整的 Apache 設定範例,讓我們逐步解析它的內容。

Apache 設定範例

以下是 VirtualHost 設定的範例檔案:

<VirtualHost *:443>
    ServerName musicevent.realnewbie.com
    DocumentRoot /path/to/your/django/project

    # 啟用 SSL
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/musicevent.realnewbie.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/musicevent.realnewbie.com/privkey.pem

    # 反向代理到 Django 服務
    ProxyPass / http://localhost:8000/
    ProxyPassReverse / http://localhost:8000/

    <Directory /path/to/your/django/project>
        Require all granted
        AllowOverride All
    </Directory>
</VirtualHost>

接下來,我們將依序解釋這些設定的作用。

Apache 設定檔詳細解析

在 Apache 的 VirtualHost 設定檔中,每個指令都有其特定的作用。以下是對每個設定項目的詳細說明,幫助你理解其功能及如何應用。

監聽 HTTPS 連線

<VirtualHost *:443>
  • VirtualHost 用於定義一個虛擬主機,Apache 會根據這個設定來處理對應的請求。
  • * 代表此設定適用於 伺服器上的所有 IP 地址,不限定特定的 IP。
  • 443HTTPS 預設使用的埠號,這表示該 VirtualHost 會監聽 HTTPS 連線。

如果你的網站要同時支援 HTTP 和 HTTPS,你還需要一個監聽 80 埠的 VirtualHost,並將 HTTP 的請求自動轉向 HTTPS:

<VirtualHost *:80>
    ServerName musicevent.realnewbie.com
    Redirect permanent / https://musicevent.realnewbie.com/
</VirtualHost>

這樣,所有 HTTP 請求都會被轉向 HTTPS,確保網站的安全性。

指定網站的網域名稱

ServerName musicevent.realnewbie.com
  • ServerName 用來 指定此 VirtualHost 負責的網域名稱
  • 當用戶瀏覽 https://musicevent.realnewbie.com,Apache 會比對 ServerName,並根據這個 VirtualHost 的設定來處理請求。

如果想讓 www.musicevent.realnewbie.com 也適用這個設定,你可以加上 ServerAlias

ServerAlias www.musicevent.realnewbie.com

這樣 www.musicevent.realnewbie.com 也會使用相同的 VirtualHost 設定。

指定網站的根目錄

DocumentRoot /path/to/your/django/project
  • DocumentRoot 用來 指定網站的根目錄,Apache 會從這個目錄提供靜態檔案。
  • 例如,如果 DocumentRoot 設定為:
DocumentRoot /var/www/musicevent
  • 那麼當使用者請求 https://musicevent.realnewbie.com/index.html,Apache 會去 /var/www/musicevent/index.html 找該檔案。

Django 注意事項

在 Apache 伺服器中,DocumentRoot 代表網站的根目錄,通常 Apache 會從這個目錄中讀取並提供靜態檔案(如 HTML、CSS、JavaScript、圖片等)。

為什麼 Django 不直接使用 DocumentRoot 來提供靜態檔案?

在傳統的 靜態網站PHP 網站 中,Apache 會將 DocumentRoot 設定為網站的根目錄,例如:

DocumentRoot /var/www/html

這表示:

  1. 所有網頁與靜態資源(HTML、CSS、JavaScript、圖片等)都直接存放在 DocumentRoot 目錄內
  2. 當使用者請求 https://example.com/index.html,Apache 會從 /var/www/html/index.html 提供該檔案
  3. 當使用者請求 https://example.com/css/style.css,Apache 會從 /var/www/html/css/style.css 提供 CSS 檔案

在這樣的架構下,Apache 會直接從 DocumentRoot 目錄讀取並提供所有靜態資源,而 後端程式(如 PHP)則與靜態檔案混合在同一個目錄內

Django 的靜態檔案管理方式不同

Django 是一個 後端框架,它的主要職責是處理動態請求,例如:

  • 資料庫存取
  • 使用者驗證
  • 伺服器端邏輯處理

Django 不會 將所有靜態檔案直接存放在 DocumentRoot,而是使用 STATIC_URL 來管理靜態資源的路徑。例如,在 settings.py 裡的靜態檔案設定:

STATIC_URL = '/static/'
STATIC_ROOT = '/path/to/your/django/project/staticfiles/'

這代表:

  1. Django 會將所有靜態檔案(CSS、JS、圖片)統一存放到 STATIC_ROOT 目錄,而不會與後端程式混合在一起。
  2. 在網頁中,Django 會使用 STATIC_URL 來定義靜態檔案的網址前綴,例如 /static/
  3. 當使用者訪問 https://example.com/static/css/style.css 時,Django 預期伺服器應該將這個請求轉向 STATIC_ROOT 內的對應檔案。
  4. Django 本身不會提供 STATIC_ROOT 內的檔案,而是讓 Apache 或 Nginx 負責這個工作
比較 Django 和 Apache 提供靜態檔案的方式
方式Apache(傳統靜態網站或 PHP)Django
靜態檔案存放目錄直接存放在 DocumentRoot 內,例如 /var/www/html/css/style.css存放在 STATIC_ROOT 內,例如 /path/to/your/django/project/staticfiles/css/style.css
伺服器如何提供靜態檔案Apache 直接從 DocumentRoot 提供Django 依賴 STATIC_URL 設定,並讓 Apache 使用 Alias 來提供檔案
需要手動收集靜態檔案嗎?不需要,直接放在 DocumentRoot 即可需要執行 python manage.py collectstatic,將所有靜態檔案集中到 STATIC_ROOT
如何讓 Apache 提供 Django 的靜態檔案?

因為 Django 不會自動處理靜態檔案的請求,所以我們必須讓 Apache 知道 STATIC_ROOT 目錄的位置,並手動設定 Apache 來提供靜態資源,例如:

Alias /static/ /path/to/your/django/project/staticfiles/
<Directory /path/to/your/django/project/staticfiles/>
    Require all granted
</Directory>

這段設定的作用:

  1. 當 Apache 收到 /static/ 開頭的請求時,它會轉向 /path/to/your/django/project/staticfiles/ 目錄,並提供對應的靜態檔案。
  2. Require all granted 允許所有使用者存取這些靜態資源,確保 CSS、JS 和圖片可以正確載入。

這樣,Django 只需要管理動態內容,而 Apache 會負責提供靜態檔案,確保網站運行更高效、更穩定。

總結
  • 傳統網站(PHP、靜態 HTML)會將靜態檔案存放在 DocumentRoot,Apache 直接提供它們。
  • Django 不會透過 DocumentRoot 來提供靜態檔案,而是使用 STATIC_URL 來管理它們的路徑。
  • Django 會將所有靜態檔案存放到 STATIC_ROOT,並需要手動讓 Apache 或 Nginx 來提供這些靜態檔案。
  • Apache 需要透過 Alias /static/ 來對應 Django 的 STATIC_ROOT,才能正確提供靜態資源。

這種架構可以提高效能,減少 Django 本身的負擔,讓靜態檔案的管理更靈活。

啟用 SSL 加密

Apache 預設不會處理 HTTPS 的請求,只有當你 啟用了 SSLEngine on,並正確設定 SSL 憑證後,Apache 才能處理 HTTPS 連線。

為什麼 Apache 預設不支援 HTTPS?

  1. HTTP 和 HTTPS 使用不同的協議與埠號
    • 預設情況下,Apache 只會監聽 80 埠(HTTP)。
    • HTTPS(443 埠)需要 SSL/TLS 加密,但 Apache 不會自動啟用 SSL,因為這需要額外的加密處理與憑證設定。
  2. SSL 需要 OpenSSL 和 mod_ssl
    • HTTPS 需要 SSL/TLS 加密,這是透過 OpenSSL 來處理的。
    • Apache 必須載入 mod_ssl 模組,才能處理 HTTPS 連線,否則即使你啟用了 SSLEngine on,Apache 仍然無法正確運行 HTTPS。
  3. 需要有效的 SSL 憑證
    • HTTPS 連線需要 憑證(Certificate)私鑰(Private Key),這些資訊不會預設存在於 Apache,因此需要手動設定。

如何讓 Apache 支援 HTTPS?

如果你希望 Apache 能夠處理 HTTPS,你需要做 三件事

  1. 啟用 SSLEngine on
  2. 安裝並啟用 mod_ssl 模組
  3. 提供有效的 SSL 憑證

完整的 Apache HTTPS 設定範例如下:

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/example

    # 啟用 SSL
    SSLEngine on

    # 指定 SSL 憑證與私鑰
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>

這樣,Apache 就能夠正確處理 HTTPS 連線,並透過 443 埠 提供加密的網站服務。

如何確認 Apache 是否已啟用 HTTPS?

1. 確認 Apache 是否已啟動 mod_ssl

使用以下指令檢查:

apachectl -M | grep ssl

如果回傳:

 ssl_module (shared)

表示 mod_ssl 已啟用,Apache 具備處理 HTTPS 的能力。

如果沒有回傳結果,則需要手動啟用:

Ubuntu / Debian

sudo apt install -y apache2 ssl-cert
sudo a2enmod ssl
sudo systemctl restart apache2

CentOS / RHEL

sudo yum install -y mod_ssl
sudo systemctl restart httpd
確保 Apache 監聽 HTTPS(443 埠)

查看 Apache 目前監聽的埠號:

sudo netstat -tulnp | grep apache

如果你看到 :443,表示 Apache 正在監聽 HTTPS,輸出示例:

tcp6   0   0 :::443   :::*   LISTEN   1234/apache2

如果沒有 :443,則需要在 Apache 設定中明確指定:

Listen 443

並重新啟動 Apache:

sudo systemctl restart apache2  # Ubuntu / Debian
sudo systemctl restart httpd    # CentOS / RHEL

指定 SSL 憑證與私鑰

SSLCertificateFile /etc/letsencrypt/live/musicevent.realnewbie.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/musicevent.realnewbie.com/privkey.pem
  • SSLCertificateFile 指定 網站的 SSL 憑證(certificate),用來加密與使用者之間的通訊。
  • SSLCertificateKeyFile 指定 私鑰(private key),用來解密 HTTPS 連線。
  • 憑證通常由 Let’s Encrypt 提供,可透過以下指令申請:
sudo certbot --apache -d musicevent.realnewbie.com
  • 成功後,Certbot 會自動產生這些檔案在 /etc/letsencrypt/live/musicevent.realnewbie.com/

6. 設定反向代理(Reverse Proxy)

ProxyPass / http://localhost:8000/
ProxyPassReverse / http://localhost:8000/
  • ProxyPass 將所有請求轉發 到本機的 Django 服務(localhost:8000)。
  • ProxyPassReverse 確保 Django 產生的重導向 URL 正確,避免用戶端出現錯誤的網址。

舉例:

sequenceDiagram
    participant User as 使用者
    participant Apache as Apache 伺服器<br>(musicevent.realnewbie.com)
    participant Django as Django 應用<br>(localhost:8000)
    
    %% 正常請求流程
    User->>Apache: 請求 https://musicevent.realnewbie.com/dashboard
    Note over Apache: ProxyPass 設定<br>ProxyPass / http://localhost:8000/
    Apache->>Django: 轉發請求到 http://localhost:8000/dashboard
    Django->>Apache: 回應處理結果
    Apache->>User: 傳送回應給使用者
    
    %% 重定向流程
    User->>Apache: 請求未授權資源<br>https://musicevent.realnewbie.com/admin
    Apache->>Django: 轉發請求到 http://localhost:8000/admin
    Note over Django: 發現未登入,需要重定向
    Django->>Apache: 回應 302 重定向到<br>http://localhost:8000/login
    Note over Apache: ProxyPassReverse 設定<br>ProxyPassReverse / http://localhost:8000/
    Apache->>User: 修正重定向 URL 為<br>https://musicevent.realnewbie.com/login
    
    %% 使用者跟隨重定向
    User->>Apache: 請求 https://musicevent.realnewbie.com/login
    Apache->>Django: 轉發請求到 http://localhost:8000/login
    Django->>Apache: 回應登入頁面
    Apache->>User: 傳送登入頁面給使用者
    
    %% 說明標籤
    Note right of User: 使用者始終只看到<br>musicevent.realnewbie.com
    Note left of Django: Django 不知道外部網址<br>使用內部網址 localhost:8000

    %% 配置說明
    rect rgb(240, 240, 240)
        Note over Apache: Apache 反向代理配置:<br>ProxyPass / http://localhost:8000/<br>ProxyPassReverse / http://localhost:8000/
    end
  1. 基本請求處理流程:
    • 使用者訪問 https://musicevent.realnewbie.com/dashboard
    • Apache 伺服器透過 ProxyPass 將請求轉發至 http://localhost:8000/dashboard
    • Django 處理請求後返回結果給 Apache
    • Apache 將結果傳回給使用者
  2. 重定向處理流程:
    • 使用者嘗試存取未授權的資源(例如管理頁面)
    • Django 發現使用者未登入,產生重定向到 http://localhost:8000/login
    • 這時 ProxyPassReverse 的重要性顯現:它將 Django 回傳的 URL 中的 localhost:8000 轉換為使用者實際看到的網域 musicevent.realnewbie.com
    • 使用者看到的重定向網址為 https://musicevent.realnewbie.com/login,而非 Django 內部使用的地址

Apache 配置關鍵點:

  • ProxyPass:
    • 將進入 Apache 的請求轉發到內部應用(Django)
    • ProxyPass / http://localhost:8000/ 意味著所有網址路徑都會被轉發
  • ProxyPassReverse:
    • 處理重定向與引用路徑,確保使用者看到的網址一致
    • 修改 HTTP 回應標頭中的 URL(如 Location, Content-Location 等)
    • 對使用者隱藏後端架構,提供無縫的使用體驗

這種設置使 Django 應用可以在內部運行,同時讓使用者通過加密的網域名稱進行訪問,實現了安全性與便利性的結合。

確保 Apache 支援反向代理 反向代理功能需要 Apache 啟用 mod_proxymod_proxy_http,可以用以下指令啟用:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2

設定 Django 專案目錄的存取權限

<Directory /path/to/your/django/project>
    Require all granted
    AllowOverride All
</Directory>
  • <Directory> 區塊用來設定 Apache 如何處理特定目錄 的存取權限。
  • Require all granted 允許 所有使用者存取該目錄
  • AllowOverride All 允許 .htaccess 覆寫 Apache 設定

.htaccess 的作用

如果 AllowOverride 設定為 All,則 Django 專案目錄下的 .htaccess 檔案可以自訂 Apache 設定。例如:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

這段 .htaccess 會強制所有 HTTP 請求轉向 HTTPS。


結論

這份 Apache 設定檔的作用是:

  1. 監聽 HTTPS(443)埠,確保網站使用 SSL 加密連線。
  2. 設定 ServerName,讓 Apache 知道如何處理特定網域的請求。
  3. 指定網站根目錄(DocumentRoot),確保靜態資源的正確存取。
  4. 啟用 SSL 憑證,使用 Let’s Encrypt 簽發的免費憑證來加密 HTTP 通訊。
  5. 透過 ProxyPass 進行反向代理,將請求轉發至 Django 應用程式。
  6. 設定 Django 目錄的存取權限,允許 Apache 正確讀取專案內容並執行 .htaccess

這些設定確保 Django 服務能夠穩定、安全地運行於 Apache 伺服器上,並透過 HTTPS 提供加密連線。🚀

設定項目說明
<VirtualHost *:443>這表示此設定適用於所有 IP,並監聽 HTTPS(443)埠。
ServerName musicevent.realnewbie.com指定此網站的網域名稱,所有該網域的請求將由此 VirtualHost 處理。
DocumentRoot /path/to/your/django/project指定網站的根目錄(實際路徑需替換)。
SSLEngine on啟用 SSL(HTTPS)。
SSLCertificateFile & SSLCertificateKeyFile指定 SSL 憑證與私鑰的路徑(通常透過 Let’s Encrypt 簽發)。
ProxyPass / http://localhost:8000/設定反向代理,將所有請求轉發至本機的 Django 服務(運行於 localhost:8000)。
ProxyPassReverse / http://localhost:8000/讓 Apache 正確回應 Django 服務的重導向請求。
<Directory /path/to/your/django/project>設定 Django 專案目錄的存取權限,Require all granted 允許所有請求,AllowOverride All 允許 .htaccess 覆寫設定。

二、如何獲取 DocumentRoot 目錄

VirtualHost 設定檔中,我們需要正確填入 DocumentRoot,也就是 Django 專案所在的目錄。如果你的 Django 專案是透過 Docker 執行,則可以依照以下方法來獲取正確的目錄路徑。

2.1 在 Docker Compose 中確認 Volume

如果你的 Django 應用程式是透過 Docker 運行,請先檢查 docker-compose.yml 中的 volumes 設定。例如:

volumes:
  - ./your-django-app:/app

這表示本機的 your-django-app 目錄對應到容器內的 /app

2.2 在本機獲取 Django 專案目錄

若要確認專案的實際路徑,可以在專案目錄下執行以下指令:

pwd

這將回傳當前目錄的完整路徑,例如:

/home/user/projects/your-django-app

這就是你需要填入 DocumentRoot 的值,例如:

DocumentRoot /home/user/projects/your-django-app
<Directory /home/user/projects/your-django-app>

三、總結

在本指南中,我們學到了:

  1. 如何設定 Apache 來反向代理 Django 服務,並啟用 SSL 憑證。
  2. 如何解析 Apache 設定檔,了解每個指令的作用。
  3. 如何獲取 Django 的 DocumentRoot 目錄,確保 Apache 能夠正確讀取專案。

透過這些步驟,你應該能夠成功設定 Apache,讓你的 Django 網站透過 HTTPS 運行,並透過反向代理來處理請求。如果在設定過程中遇到問題,可以檢查 Apache 日誌(通常位於 /var/log/apache2/error.log)來進一步排除錯誤。

希望這篇指南對你有所幫助,祝你的 Django 部署順利!🚀

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *