文前碎碎念
雖然自己在很早以前就已經設定好一隻可以完整運作的 Linebot 了,但當時也是東湊西幹的,廢了一番功夫才摸出讓它執行的路徑,但時間一久,也就發現根本忘記當初怎麼處理了。
而好死不死,近期又接了另一隻機器人的開發,無奈只好再重新折騰一次,不過這樣也好,除了複習技術外,也趁這個機會將過程紀錄一下吧!註1:本篇主要為筆記性質,且主要著重於伺服器通用設定步驟,部分繁瑣步驟有做簡化,建議視情況作為參考。
註2:由於本篇操作為協助別人建立的專案,較不方便公開實際內容,因此無截圖僅指令紀錄,請見諒。
行前注意
要架設一隻上線版的機器人,首要步驟就是要準備一台能夠確保 24 / 7 運作的伺服器,而經過我多家比較後,最終我選擇的是 Linode 這家老牌公司做託管。
Linode 是一家美國的虛擬 Linux 伺服器提供商,由 Akamai Technologies 於 2022 年三月併購成為其母公司。
不過關於伺服器選擇,可能有人會問說現在解決方案那麼多,我大可把東西丟給 AWS、Google 雲端,用模組、AI 方式去管理就好啦,幹嘛要自己弄伺服器呢?
哀⋯⋯我只能說,除了想要更多客製化的自由度外,其他一切都是「成本」考量阿。
就以 AWS 來說,伺服器運算是以 Runtime 時間來計費,資料存儲那些也要額外計費,反觀 Linode 的伺服器租用,除了大量運算的 GPU Host 外,他還有提供一個月 5 美金的 Nanode 1 GB Shared CPU 方案。
這個方案的基本規格就有 1 GB 的 RAM、25 GB 的存儲空間以及 1 TB 的傳輸量,傳輸也有 40/1 Gbps 的 In / Out 速度,以一個小型專案來說十分足夠,其他的方案選擇可以參考它的方案列表。
不過相對缺點,就是一切都是從零開始,因為伺服器預設是一個完全空白的 Linux 系統,所以包含系統套件、安全連線、檔案結構管理那些都要自己弄,可能也算是一種「等價交換」吧(?
不過由於每個人專案的需求,與選擇條件差異頗大,而 Linode 的申請也蠻直覺的,因此購置或租用伺服器的流程,就不多做說明了。
這裡就假設看到這篇的朋友,都已經完成基本的硬體與系統準備,直接來檢視目前的機器人架構吧!
機器人本體
Flask 架構
這次我所開發的機器人,是以 Python Flask 為基礎,所以首要條件,就是確保新系統上已完成所有相關的依賴套件。
不過 Flask 框架本身是個輕量化結構,用來快速建立測試用專案固然方便,但如果要實際公開使用的話,就可能就會遇到高負載問題了。
因此我們部署前,需要加上一個 WSGI(Web Server Gateway Interface)來更有效率的處理使用者 Request,這裡就使用 Waitress 這個套件來處理。
from waitress import serve
from flask import Flask
from dotenv import load_dotenv
from linebot.v3 import WebhookHandler
from linebot.v3.exceptions import InvalidSignatureError
app = Flask(__name__) #Set flask app
# Load .env as Enviroment Setting
load_dotenv(os.path.join(baspat,'.env'))
# Linebot Config
configuration = Configuration(access_token=os.environ['TOKEN'])
handler = WebhookHandler(os.environ['SECRET'])
## Callback For Linebot
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
'''
Whatever Your Project Do
'''
if __name__ == "__main__":
#Original Starting Method
#app.run()
#Serve Application With Waitress on Port 8000
serve(app, host="0.0.0.0",port="8000")
上面範例是我的 Linebot 的最簡模板,其實要把負載處理換掉所需修改的內容不多,只要把 Waitress 導入後,再把最後指令更換成以waitress serve來啟動應用即可,其餘 Line Bot 詳細開發步驟,由於不是本篇重點也不再贅述,可以參考 Line 的官方開發說明,依自己需求進行編寫。
設為 Service
接下來這步驟,其實並非必要,只是如果直接將 Bot 服務設為 Service 的話,就可以讓他在系統開機後,由系統自動在背景執行,這樣就不用特別再去下指令啟動了。
設定 Service 第一步,先使用以下指令建立新的設定檔,注意這裡根據要啟用的身分種類,儲存的目錄也有所不同,執行時可獲得的權限也不一樣,請根據專案需求來選擇。
# For system (sudo)
sudo nano /lib/systemd/system/SERVICE_NAME.service
# For User
sudo nano /lib/systemd/user/SERVICE_NAME.service
設定檔內容,可以使用下面範本來做修改,主要達成效果為 Service 啟動後,會自動用指定路徑下的 Python 版本來執行你的 Flask 服務,而如果程式意外 Crash 過三秒後,便會自動嘗試重啟,以及接收「Ctrl + C」訊號為終止程式的 KillSignal。
[Unit]
Description=<YOUR_SERVICE_DESCRIPTION>
[Service]
Type=simple
ExecStart=/usr/bin/python3 <PATH_TO_PY_SCRIPT>
Restart=always
RestartSec=3
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
要注意的是,如果你的程式執行環境如果是用另外建立的虛擬環境(venv)的話,在ExecStart這項的 Python 路徑,就要改成當初建立環境所指定的位置,例如/home/USER_NAME/VENV_PATH/bin/python3。
接著用下面兩行指令,分別賦予 Service 檔執行權限,並重整系統服務。
sudo chmod 644 /lib/systemd/system/Service_Name.service
# Reload Services
sudo systemctl daemon-reload
完成之後,就可以直接用以下指令來控制服務的開關,還有顯示狀態啦,這裡同樣要注意專案是需要以哪種權限開啟來調整對應指令。
# For system (sudo)
sudo systemctl [enable/disable/start/stop/restart] Service_Name.service
# For User
systemctl --user [enable/disable/start/stop/restart] Service_Name.service
其中[]內選項請自行切換,分別是【啟用】、【停用】、【執行】、【停止】、【重啟】指令,例如要啟用服務的話,就輸入這一行。
sudo systemctl enable Service_Name.service
這樣一來,只要系統重啟後,機器人服務也就會跟著啟動了。
Nginx 伺服器
完成機器人的 Application Server 設定後,接著就是設定 Web Server 來做反向代理,平衡負載以及將客戶端請求轉送到正確的 Port 去做處理,而在這次專案中,我選用的是 Nginx 這個常見的高效率套件來架設。
首先是安裝指令
sudo apt install nginx接下來就是建立 Bot Flask 伺服器的設定檔
sudo nano /etc/nginx/sites-enabled/<BOT_NAME>
其中<BOT_NAME>替換成自己機器人專案的名稱,正常來說應該會直接開啟一個新的檔案,接著在裡面新增下面這一段。
server {
server_name <LINODE_URL>;
location /static {
root <FLASK_SERVER_STATIC_PATH>;
}
location / {
proxy_pass http://localhost:8000;
include /etc/nginx/proxy_params;
proxy_redirect off;
}
}
貼上後,將<LINODE_URL>替換成自己 Linode 虛擬機的對外 IP 或是完整網址(可以從 Linode 後台的 Networks 中 Public – IPv4 這項看到)。
而<FLASK_SERVER_STATIC_PATH>則是剛剛 Flask 伺服器的 static 資料夾路徑,完成修改之後按下 Ctrl+X 儲存檔案後退出。
接著把預設的設定檔,用 unlink 指令從sites-enabled解除連結,然後重新載入 Nginx 的設定。
# Unlink Default Config
sudo unlink /etc/nginx/sites-enabled/default
# Reload Nginx
sudo nginx -s reload
如果前面的 Flask 程式有加入可瀏覽的 index 的話,以上步驟設定完成後,使用瀏覽器打開 Linode 的對外網址,應該就可以看到正常的網頁了。
SSL 認證
雖然說到上一步後,基本上其他人就能使用 Linode 的外部連結來訪問你的網頁了,不過沒有 SSL 認證的話,在瀏覽的時候會被系統警告為不安全(非 HTTPS)的連線。
另外如果是作為 Line Bot 的後台伺服器的話,Line 的開發中也有要求伺服器端必須要有安全連線才可以通過後台的認證。
要在自己的伺服器上建立 SSL 驗證,最快速免費的做法,就是使用 Let's Encrypt 這個推廣 HTTPS 簽署服務的 Certbot 工具了。
這裡以 Linode 上的 Ubuntu 主機為範例,首先以下面指令更新安裝 UFW 防火牆。
sudo apt update
sudo apt install ufw
接著設定指令開啟 SSH(22)、HTTP(80) 及 HTTPS(443) 三個 Port。
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
最後啟用 UFW 並確認是否正常運作。
sudo ufw enable
sudo ufw status
至此防火牆設定大致完成,接下來就是安裝 snap 這個套件管理器,以及他的主要套件。
# Update Package and Install snapd
sudo apt update
sudo apt install snapd
# Use snap Install core
sudo snap install core
sudo snap refresh core
接著就能用 snap 安裝 Certbot 了,不過要記得先確定沒有其他版本在系統內。
sudo snap install --classic certbot
接著就可以下指令開始建立憑證,這裡因為我們的機器人伺服器是用 Nginx 作為 Host,所以要加一個附帶參數,他就會自動修改 Nginx 的設定檔。
sudo certbot --nginx
開始流程後,會需要閱讀同意項目,並且輸入一些基本資訊,如名稱、Email 等,接著會讓你選擇要認證的網址,我這裡可能是在前面 Nginx 中有設定,所以有直接列出 Linode 的對外網址,選擇後等他執行完成,基本上就可以了,最後使用瀏覽器確認一下,應該可以看到警告消失了。
不過這個方式取得的憑證只有三個月(90天)的效期,需要定時更新,而根據說明,正常情況下 Certbot 會自動進行更新,如果要確認更新功能是否正常,可以使用下面的指令。
sudo certbot renew --dry-run而如果要手動更新的話,直接輸入這個指令即可。
sudo certbot renew以上步驟完成後,就可以到 Line 的開發者後台去做驗證啦!
結語
這次筆記就差不多到這裡,其實嚴格說起來,應該也是有不少細部的東西沒有多做說明紀錄,像是後要接上自己的網域,或是更進階的連線限制,那就又是另一個故事了,不過畢竟這次的專案也是屬於重啟設定而已那就就先這樣吧。
不過這種資訊技術類的東西,還真的不能擱置太久不去管他,不然那個生疏感是很恐怖的,就跟回頭看自己在數個月前寫的程式碼一樣,心裡只會有滿滿的問號,跟想回到過去揍自己一拳的慾望(?
而現在生成 AI 的崛起,固然在開發上會帶來不少便利,但對於要長久維運的專案來說,依然會有與舊有架構難以快速整合,而新架構在不理解的情況下難以維護的困境。
總之,這篇就當作是給未來自己留的一份備忘錄吧,也希望這樣的資料整理可以幫助到有需要的開發者囉,而如果有任何遺漏或錯誤的話,也歡迎留言指教~





















