在前一篇測試中利用站台設定檔的 location 區塊定義不同的 URL 路徑來執行不同的 Flask 網頁應用程式, 如果要執行更多的 app, 只要在站台設定檔中新增子路徑轉發到 Gunicorn 監聽的埠即可. 本篇則是要改用子網域的方式來達成相同功能.
子網域乃是主網域的一部分, 例如在 blog.example.com 網址中, blog 就是一個子網域. 在結構上, 主網域是整個域名的基礎, 而子網域是建立在主網域之上的額外層級; 在功能上, 主網域通常代表整個網站, 而子網域則用來提供特定的內容或服務 (例如部落格, 商店或客戶服務等), 它們可以在同一主網域下運行不同的應用程序或功能.
我計畫在 Mapleboard 上佈署多個 Flask app 作為 LINE Bot 的 webhook, 但又想保留主網域 tony1966.cc 來架設個人網站或部落格, 因此初步規劃在 Namecheap 新增一個子網域 flask.tony1966.cc 當作 webhook 後台伺服器網址, 搭配子路徑可以佈署多個 Flask app. 將 app 放在個別子網域下可方便管理和區分不同類型的服務.
本篇旨在將前一篇以獨立站台設定檔 hello 的子路徑執行兩個 app 的方式改成用 flask.tony1966.cc 子網域來達成.
1. 新增子網域 flask.tony1966.cc :
首先登入 Namecheap 首頁 :
按 SIGN IN 輸入帳密登入網站 :
按 Dashboard 下的 Domain List, 再按域名列表最右邊的 Manage 鈕進入管理頁面 :
按最右邊的 Advanced DNS :
按底下的 Add new record 新增一筆紀錄 :
Type 欄勾選 CNAME record, Host 欄填入 flask, Value 欄填入主域名 tony1966.cc, TTL 欄用預設 Automatic 即可, 按底下的打勾勾按鈕即完成新增設定 :
這樣就完成 Namecheap 域名管理平台上的子網域 flask.tony1966.cc 的設定了, 最快幾分鐘內就會生效, 但因為 DNS 更改需要時間在全球的 DNS 伺服器間傳播, 最高可能須等待 48 小時. 可以用 dig 指令向 DNS 伺服器查詢此域名是否已生效會查詢 flask.tony1966.cc 這個域名的 DNS 資訊, 包括其 IP 地址, 名稱伺服器, MX 記錄等 :
tony1966@LX2438:~$ dig flask.tony1966.cc
; <<>> DiG 9.18.24-0ubuntu0.22.04.1-Ubuntu <<>> flask.tony1966.cc
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24124
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;flask.tony1966.cc. IN A
;; ANSWER SECTION:
flask.tony1966.cc. 1799 IN CNAME tony1966.cc.
tony1966.cc. 1799 IN A 220.133.12.159
;; Query time: 126 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Mon Jul 14 09:56:40 CST 2025
;; MSG SIZE rcvd: 76
"status: NOERROR" 表示查詢成功, 沒有錯誤. ANSWER SECTION 中的 "flask.tony1966.cc. 1799" 表示有效期為 1799 秒, 已效期就是該 DNS 記錄的 TTL (Time to Live) 值, 在這段時間內, 當其他用戶查詢相同的域名時將不需要再次向上游的 DNS 伺服器發送請求, 而是直接使用記憶體暫存的結果, 這樣可以提高查詢效率並減少網絡流量.
2. 檢視 Gunicorn 程序 :
在前兩篇測試中已在 ~/flask_apps 資料夾下建立兩個 Flask app : hello.py 與 hello2.py, 並且啟動 Gunicorn 程序分別監聽 127.0.0.1:8080 與 127.0.0.1:8081 埠, 當 Nginx 轉發 HTTP 請求到這兩個埠時便分別執行 hello.py 與 hello2.py 來回應. 終端機的啟動指令如下 :
gunicorn -w 4 -b 127.0.0.1:8080 hello:app
gunicorn -w 4 -b 127.0.0.1:8081 hello2:app
可用下列指令查詢目前執行中的 Gunicorn 程序 :
tony1966@LX2438:~$ ps aux | grep gunicorn
tony1966 223187 0.0 0.2 34156 8960 ? Ss Jul06 4:35 gunicorn: master [hello:app]
tony1966 223192 0.0 0.6 42348 24188 ? S Jul06 0:29 gunicorn: worker [hello:app]
tony1966 223193 0.0 0.6 42344 23988 ? S Jul06 0:28 gunicorn: worker [hello:app]
tony1966 223194 0.0 0.5 42344 20256 ? S Jul06 0:29 gunicorn: worker [hello:app]
tony1966 223195 0.0 0.6 42344 24076 ? S Jul06 0:29 gunicorn: worker [hello:app]
tony1966 418476 0.0 0.5 34156 19908 pts/0 S+ Jul14 0:26 gunicorn: master [hello2:app]
tony1966 418477 0.0 0.6 41156 25636 pts/0 S+ Jul14 0:02 gunicorn: worker [hello2:app]
tony1966 418478 0.0 0.6 41320 26136 pts/0 S+ Jul14 0:02 gunicorn: worker [hello2:app]
tony1966 418479 0.0 0.6 41156 25604 pts/0 S+ Jul14 0:02 gunicorn: worker [hello2:app]
tony1966 418480 0.0 0.6 41156 25624 pts/0 S+ Jul14 0:02 gunicorn: worker [hello2:app]
tony1966 440626 0.0 0.0 9136 1712 pts/1 S+ 11:43 0:00 grep --color=auto gunicorn
也可以將啟動 Gunicorn 程序設為系統服務 (systemd), 這樣就不會占用一個終端機, 且萬一系統當機重啟後也會自動啟動, 參考 :
3. 建立網站設定檔 flask.tony1966.cc :
接下來要為子域名 flask.tony1966.cc 建立一個獨立的網站設定檔, 為了清楚辨識與日後維護方便, 檔名就取與子域名相同的 flask.tony1966.cc, 這樣一眼就知道這個設定檔是對應哪個子網域.
用 nano 編輯 /etc/nginx/sites-available/flask.tony1966.cc 設定檔 :
tony1966@LX2438:~$ sudo nano /etc/nginx/sites-available/flask.tony1966.cc
[sudo] tony1966 的密碼:
輸入如下之初始內容 :
server {
listen 80;
server_name flask.tony1966.cc;
location /hello/ {
proxy_pass http://127.0.0.1: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;
}
location /hello2/ {
proxy_pass http://127.0.0.1:8081/;
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;
}
}
此初始內容為對子網域 flask.tony1966.cc 的 HTTP (80 埠) 請求之轉發設定, 利用 proxy_pass 指令將不同子路徑 (/hello/ 與 /hello2/) 的請求轉發到上游 Gunicorn 伺服器的不同端口埠號 (8080 與 8081).
4. 建立符號鏈結啟用網站設定檔 flask.tony1966.cc :
接下來用 ln -s 指令建立網站設定檔 flask.tony1966.cc 在 /etc/nginx/sites-enabled/ 下的符號連結來啟用此子網域站台 :
tony1966@LX2438:~$ sudo ln -s /etc/nginx/sites-available/flask.tony1966.cc /etc/nginx/sites-enabled/
[sudo] tony1966 的密碼:
用 ls -ls 檢視 /etc/nginx/sites-enabled/ 下的已啟用站台 :
tony1966@LX2438:~$ ls -ls /etc/nginx/sites-enabled/
總用量 0
0 lrwxrwxrwx 1 root root 44 Jul 15 14:09 flask.tony1966.cc -> /etc/nginx/sites-available/flask.tony1966.cc
0 lrwxrwxrwx 1 root root 32 Jul 7 15:23 hello -> /etc/nginx/sites-available/hello
可見已啟用了 flask.tony1966 站台.
5. 檢查網站設定檔與重新載入 Nginx :
用 nginx -t 指令測試 Nginx 在 /etc/nginx/sites-available/ 下的所有網站設定檔, 看看是否有語法錯誤以及配置是否正確 :
tony1966@LX2438:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
沒有錯誤就重新載入 Nginx :
tony1966@LX2438:~$ sudo systemctl reload nginx
6. 使用 Certbot 自動加入 HTTPS 設定 :
因為主網域 tony1966.cc 有向 Let's Encrypt 註冊來取得 HTTPS (443 埠) 安全網站連線 SSL/TLS 憑證, 上面的子網域站台設定檔僅配置了 HTTP 的設定, 必須用 Let's Encrypt 提供的工具程式 Certbot 來為子網域 flask.tony1966.cc 加上 HTTPS 設定, 指令如下 :
sudo certbot --nginx -d flask.tony1966.cc
tony1966@LX2438:~$ sudo certbot --nginx -d flask.tony1966.cc
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for flask.tony1966.cc
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/flask.tony1966.cc/fullchain.pem
Key is saved at: /etc/letsencrypt/live/flask.tony1966.cc/privkey.pem
This certificate expires on 2025-10-13.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for flask.tony1966.cc to /etc/nginx/sites-enabled/flask.tony1966.cc
Congratulations! You have successfully enabled HTTPS on https://flask.tony1966.cc
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
用 cat 檢視 Certbot 修改過的站台設定檔 flask.tony1966.cc :
tony1966@LX2438:~$ cat /etc/nginx/sites-available/flask.tony1966.cc
server {
server_name flask.tony1966.cc;
location /hello/ {
proxy_pass http://127.0.0.1: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;
}
location /hello2/ {
proxy_pass http://127.0.0.1:8081/;
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;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/flask.tony1966.cc/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/flask.tony1966.cc/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = flask.tony1966.cc) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name flask.tony1966.cc;
return 404; # managed by Certbot
}
可見 Certbot 已加入 HTTPS 的安全連線設定了.
目前啟用的 hello 與 flask.tony1966.cc 這兩個站台對來自客戶端的請求之轉發流程如下 :
客戶端的 HTTP/HTTPS 請求
↓
Nginx (80/443 埠)
↓ 根據 server_name 判斷是哪個網域
|__ tony1966.cc (設定檔 hello)
| ↓ 根據 location 的路徑判斷要轉發到哪個端口
| |__ / → http://127.0.0.1:8080 (執行 hello.py)
| |__ /hello2/ → http://127.0.0.1:8081 (執行 hello2.py)
|
|__ flask.tony1966.cc (設定檔 flask.tony1966.cc)
↓ 根據 location 的路徑判斷要轉發到哪個端口
|__ /hello/ → http://127.0.0.1:8080 (執行 hello.py)
|__ /hello2/ → http://127.0.0.1:8081 (執行 hello2.py)
可見這兩個站台其實都把請求轉發到相同的 Gunicorn 端口.
7. 測試網站 :
以上完成子網域站台 flask.tony1966.cc 的設定後測試下列網址 :
子網域 flask.tony1966.cc 站台建置好後就可以在此子網域下寫 app 了 (例如 LINE Bot 的 webhook), 每新增一個 app 就要在網站設定檔 flask.tony1966.cc 中新增一個 location 區塊並為此 app 指定一個 Gunicorn 轉發端口埠號.









沒有留言 :
張貼留言