Tech Stack
- Linux(Ubuntu 20.04+) 主機:本專案不使用雲端 PaaS 服務(Heroku、Azure、GCP),而是自行架設 Linux 主機進行多個專案的維護
- systemd:管理多個系統服務
- SSH:遠端連線管理,如 OpenSSH)
- Nginx:Web Server,反向代理
- uWSGI:Django WSGI 伺服器,Django 與 Web Service 之間的接口
網路上部署教學非常多,但 95%都是教怎麼透過第三方部署平台例如 Heroku,Azure,GCP
…等,但我就是想架在自己架設的 Ubuntu 主機上阿!而關於各式部署方法及各自的優缺點我會再另外寫一篇文章,此篇就不多加贅述
DNS 基礎知識
當使用者輸入 Domain Name 後,Web 必須要先去一台有 Domain Name 和 IP 對應資料的主機去查詢這台電腦的 IP,而這台被查詣的主機為 Domain Name Server
,簡稱 DNS.
Ex:當你輸入
www.shopee.com.tw
時,Web 就會將www.shopee.com.tw
傳送最近的 DNS Server 去做辨識,若查詢有結果,則會傳回這台主機的 IP,進而跟它索取資料,若沒查到,就會發生 DNS NOT FOUND 的情形,而每個 Domain Name 對應要一組 IP,且 Domain Name 跟 IP 一樣不會重覆
一般架設網站時不管是 Code from Scratch 還是用 Wordpress 等都需申請 DNS 指向你的 IP,畢竟大家也不可能去記 IP 位址來找網站,申請完後才辦法讓自己以外的人找到你自行定義的網域
購買網域
我購買網域的平台為 cloudflare,個人認為他的平台是我用過 UI 最人性化且支援暗黑模式的,未來有購買網域需求不妨去 Cloudflare 網域管理平台 看看
Cloudflare 設定
在 akebee 主網域下新增一個子網域 niceshop.akebee.com,並設定 SSL/TLS 加密
測試是否網域已生效
可透過 nslookup
來查看 DNS 設定是否生效
1 | nslookup niceshop.akebee.com |
若成功就會顯示:
1 | Server: 1.1.1.1 |
若網路環境或主機設定有防火牆或其他限制
,可能會導致從遠端無法連接到你的主機,也就是說用 0.0.0.0:8000 去 runserver 反而會連不到。我的情況就是只有內部網路能存取
1 | #settings.py |
ALLOWED_HOSTS
預設為空白,意思就是除了 localhost 以外其他的外部 IP 都無法連上這個網站
資料庫設定
sqlite3
是 Django 預設的資料庫,開發階段還能用,但在正式環境中,會採用 MySQL 或 PostgreSQL 作為正式的資料庫較合適
1 | # settings.py |
建立 Virtual Enviornment(虛擬環境)
連線至自己的主機,安裝並建立一個獨立的虛擬環境,避免不同專案之間的套件衝突
1 | sudo apt-get install python3-venv |
uWSGI
作為 應用伺服器(WSGI Server),負責處理來自 Nginx 的請求,並透過 WSGI 協定與 Django 互動,執行 Python 程式並回應結果。
uWSGI 與 Gunicorn 比較
比較項目 | uWSGI | Gunicorn |
---|---|---|
開發語言 | C | Python |
設定難度 | 較複雜,支援 .ini 配置文件 | 簡單,CLI 參數即可 |
效能 | 效能高,可微調許多參數 | 效能可,適合中小型應用 |
擴展性 | 非常強,支援 WSGI、FastCGI、HTTP、SMTP 等多種協議 | 專注於 WSGI,簡單易用 |
內建功能 | 支援 Emperor 模式、記憶體快取、自動重啟等 | 內建功能較少,依賴第三方工具 |
應用場景 | 適合大規模、高度可調整的專案 | 適合大多數 Web 應用,特別是 REST API 服務 |
穩定性 | 高度可調整,但需要正確配置 | 默認設定已經適用大多數場景 |
uWSGI 配置
先在虛擬環境安裝 uWSGI
1 | # |
切記註解「不要」寫在行後面,否則會解析到註解的內容
1 | [uwsgi] |
uwsgi_params
此檔案是在專案目錄底下/home/httpd/niceshop
建立 uwsgi_params
- 用於定義轉發到 uWSGI 服務器的 HTTP 請求參數。
- 此文件列出了所有必要參數,以便 Nginx 可以通過正確的方式將請求傳遞給 uWSGI。
- 例如:QUERY_STRING 定義了 HTTP 請求中的查詢字符串。uWSGI 需要這些變量來識別請求的內容,並正確地將其轉發到相應的應用程序。
1 | # /home/httpd/niceshop/uwsgi_params |
常用 uWSGI 指令
指令 | 功能 |
---|---|
sudo systemctl start uwsgi | 啟動 uWSGI |
sudo systemctl restart uwsgi | 重新啟動 uWSGI |
sudo systemctl stop uwsgi | 停止 uWSGI |
sudo systemctl status uwsgi | 查看 uWSGI 運行狀態 |
sudo systemctl enable uwsgi | 設定開機自動啟動 |
sudo systemctl disable uwsgi | 取消開機自動啟動 |
sudo journalctl -u uwsgi --no-pager --lines=50 | 查看 uWSGI 錯誤日誌 |
sudo journalctl -u uwsgi -f | 監聽 uWSGI 日誌 |
sudo tail -f /var/log/nginx/niceshop.error.log | 查看 Nginx 錯誤日誌 |
Nginx 設定檔
反向代理伺服器,負責處理靜態文件(如 HTML、CSS、JS)並將動態請求(如 API 請求)轉發至應用伺服器
這邊的做法是先忽略 Nginx
及 uWSGI
的設定,直接透過 python manage.py runserver
來啟動 Django 伺服器,然後透過 Nginx
來代理 Django 伺服器。
1 | # /etc/nginx/sites-available/niceshop |
測試環境 vs 正式環境差異
主要就差在 nginx 設定檔中的 proxy_pass
設定不同
測試環境:
1 | location /api/ { |
正式環境:
1 | location /api/ { |
新增 Nginx 代理 /django-admin/ 到 Django
前面忘記新增讓 Nginx 代理 Django Admin 的設定,導致想訪問 Django 預設 Admin 頁面時一直導回首頁,所以新增以下設定
1 | # 新增這一段 (代理 Django Admin) |
還是要有這個能更好的管理後台
測試 uWSGI 是否能讓網站正常運行
至專案目錄底下執行
1 | cd /home/httpd/niceshop |
可以跑就可以改成用 systemd 來管理 uWSGI 服務,而不是每次都透過手動啟動
使用 systemd 讓 uWSGI 開機自動啟動
建立一個 systemd 服務,這樣即使伺服器重啟,uWSGI 也能自動啟動並保持運行。
1 | sudo vim /etc/systemd/system/uwsgi.service |
編輯 uwsgi.service
檔案,輸入以下內容:
1 | [Unit] |
📌 確保:
- ExecStart 指向 虛擬環境內的 uWSGI(/home/httpd/django_venv/bin/uwsgi)
- User=www-data & Group=www-data,
避免用 root 執行
最後 啟用並啟動 uWSGI 服務:
1 | # 重新載入 systemd |
大功告成
Django、Cloudflare、Nginx、uWSGI 的設定都已經完成,現在就可以透過外部去瀏覽網站了!
常見問題
啟動 uwsgi 報錯:ImportError: No module named ‘pymysql‘ 解決方法:
uwsgi
用到系統的 python,而不是虛擬環境的 python,所以需要在虛擬環境中安裝 pymysql
1 | source /home/httpd/django_venv/bin/activate |
若回傳如下,代表 uwsgi
用到的 python 是系統的 python,而不是虛擬環境的 python
1 | /home/httpd/django_venv/bin/python |
no module named ‘pymysql’
1 | python3 -m pip install pymysql --upgrade |
bind(): Permission denied [core/socket.c line 230]
這問題時常出現在啟動 uWSGI sudo systemctl start uwsgi
時,通常是因為 uWSGI 沒有權限在指定的目錄下創建 socket 文件,解決方法是修改 socket 文件的權限:
1 | sudo chown -R www-data:www-data /home/httpd/niceshop |
uwsgi.service 啟動失敗,錯誤碼 203/EXEC
大多是因為先前不小心直接用 root 身份去執行 uwsgi,導致權限被改變,uwsgi.service 是用 www-data 用戶和組,所以要改回來
1 | # 重新啟用 uwsgi |
補充(非必要)
Emperor mode
何謂emperor mode
?一般會在大型專案開發時遇到,在這種模式下,uWSGI 啟動一個特殊的 master 進程,稱為"emperor",該進程可以監控一個或多個虛擬主機或應用程序的進程。
這些虛擬主機或應用程序可以是不同的 Python 應用程序,也可以是不同的框架或應用程序。有興趣了解他的功能可以直接去看官方 docs
1 | # 去 django_venv 目錄下新增 vassals 資料夾 |
更改 uwsgi.ini 的 uwsgi-emperor.log 位置
由於原本我的 uwsgi-emperor.log 的位置是跟其他專案一起放在/home/httpd/
之下,我覺得有點亂,因此我就想將換到/home/httpd/django_venv/vassals/
底下。
1 | # 編輯 uwsgi.ini |
改完路徑後還沒完,此時直接用 emperor mode 執行 uwsgi 會出現permission denined
的問題,代表他沒有權限可以編輯uwsgi-emperor.log
檔案。
1 | # 原本的權限狀態 |
這樣做的目的是為了確保 uwsgi 服務可以以 www-data 用戶和組的身份運行,這樣 uwsgi 就可以擁有對/home/httpd/django_venv/vassals/
目錄和其子目錄的讀取、寫入和執行權限。此時再執行uwsgi --emperor /home/httpd/django_venv/vassals/ --uid www-data --gid www-data
應就能看到預設畫面了
若您覺得這篇文章對您有幫助,歡迎分享出去讓更多人看到⊂◉‿◉つ~
留言版