在 Ubuntu 上部署適合上線的單機 NodeBB 論壇服務

發布: 約 20 分鐘

本文山姆鍋分享如何安裝與設定一個 NodeBB 論壇的正式生產環境(production environment)。由於整個環境不只包含 NodeBB 本身,會從主機系統的開始設定開始到 Nginx web 服務。安裝過程參考了多篇文章,對於特定元件的安裝細節會直接連結到對應的教學文章,本文盡量只做重點說明。

歡迎您加入 #Developers.TW ⎘ ,A.K.A. #呆丸開發者。

目錄

展開目錄

安裝目標

本文是以 #Developers.TW ⎘ 作為實際案例,並以符合需求的最少安裝為目標。選擇性的元件,如 iframely 網頁內嵌剖析或者 Solr 搜尋服務並不在本文說明。因為目標是可用在正式上線的最小安裝,擴充性、可用性等等自然也就先不要求了。

下圖是部署完成後粗略的系統架構圖:

NodeBB Deployment

準備工作

底下是一些 NodeBB 論壇安裝設定需要的前置需求:

  1. 有 NodeBB 論壇的專屬域名或子域名,像 #Developers.TW 的域名是 developers.tw。
  2. 域名服務器已經設定完畢。本文是採用 CloudFlare 作為 DNS 以及 CDN 服務供應商。
  3. 讀者知道如何設定域名的 DNS 紀錄。
  4. 部署使用的工作機(筆電或者PC)已經有 SSH 登入的金鑰對(key pair)。

主機系統

對於經濟實惠又需要完整系統的部署環境,山姆鍋通常都會選用 DigitalOcean 的 VPS 虛擬私有伺服器,這次也不例外,選用一個標準型 1GB 記憶體、1核 vCPU 的 Droplet 作為部署環境。

註冊 DigitalOcean 帳戶以及建立一個 Droplet 可以參考 Digital Ocean: 申請自己的虛擬主機伺服器 ⎘。

基本環境 (Ubuntu 18.04)

項目方案
主機環境DigitalOcean Droplet
主機組態1 core vCPU, 1GB RAM, 25GB SSD
作業系統Ubuntu 18.04 64-bit

郵件寄送

強烈建議使用雲端電子信件寄送服務,不要在主機自行安裝 Postfix, Exim 等郵件軟體。現在雲端郵件寄送服務功能完整、成功送達率較高,又有每月免費使用額度。#Developers.TW 使用的是 SendGrid 提供的郵寄服務,只是因為山姆鍋有使用經驗,讀者可以選擇自己熟悉的服務。

不管採用哪個服務,需要取得下列郵件寄送服務的網路參數:

項目說明
SMTP 伺服器位址IP 或域名
SMTP 監聽埠如 487
SMTP 登入名稱SendGrid 使用 ‘apikey’ 作為登入名稱
SMTP 登入密碼從 SendGrid 申請的 api key 內容

有了雲端郵件寄送服務後,要讓主機系統可以寄出信件,尚須安裝與設定下列套件:

  • mailutils
  • ssmtp

使用下列指令安裝:

$ sudo apt-get install mailutils ssmtp

ssmtp 需要根據雲端郵寄服務提供的網路參數來設定,底下是 /etc/ssmtp/ssmtp.conf 檔案的內容:

#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=sam@example.com   # 管理者的 email

# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=smtp.sendgrid.net:587 # 雲端郵件寄送服務提供接口

# Where will the mail seem to come from?
#rewriteDomain=
rewriteDomain=developers.tw  #改寫收件人看到的郵件來源域名

# The full hostname
hostname=nodebb-test   # 主機名稱

# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
#FromLineOverride=YES

AuthUser=apikey             # SMTP 登入名稱
AuthPass=xxxxxxxxxx         # SMTP 登入密碼

UseSTARTTLS=YES
UseTLS=YES

餐考文章:

安全強化

完成主機系統的基本安裝後,作為網路服務主機,主機安全性也不容輕忽。

SSH

底下是一些安全強化重點(只是基本):

  1. 只允許使用憑證 SSH 遠端登入主機,禁用密碼。
  2. SSH 不允許直接以 root 帳戶登入。
  3. (選擇性) 更改 SSH 服務的監聽埠(port),例如:939:這個不會增加多少安全性,但可以有效減少系統日誌的被攻擊的紀錄。

參考文章:

自動更新安全修補

當主機系統被發現有安全漏洞時,山姆鍋希望能夠自動更新修補程式。採考此文章 How To Setup And Enable Automatic Security Updates On Ubuntu ⎘ 。

安裝 unattended-upgrade 套件

使用下列指令安裝 unattended-upgrade 套件:

$ sudo apt install unattended-upgrades

unattended-upgrades 的設定檔為 /etc/apt/apt.conf.d/50unattended-upgrades,山姆鍋直接使用預設值。如果需要增加自動更新的套件庫(repository),可以用文字編輯器修改此文件,移除對應行前 // 註解符號。

Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
  "${distro_id}:${distro_codename}-security";
  // Extended Security Maintenance; doesn't necessarily exist for
  // every release and this system may not have it installed, but if
  // available, the policy for updates is such that unattended-upgrades
  // should also install from here by default.
  "${distro_id}ESMApps:${distro_codename}-apps-security";
  "${distro_id}ESM:${distro_codename}-infra-security";
  //	"${distro_id}:${distro_codename}-updates";
  //	"${distro_id}:${distro_codename}-proposed";
  //	"${distro_id}:${distro_codename}-backports";
};

啟用自動更新

/etc/apt/apt.conf.d/20auto-upgrades 設定檔控制系統自動更新的行為。

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInternal "7";

其中,“1” 表示啟用,要禁用則改為 “0”。

測試自動更新

使用下列指令進行空轉測試:

sudo unattended-upgrades --dry-run -–debug

會顯示類似下面的結果:

... 前面省略

adjusting candidate version: python3-zope.interface=4.3.2-1build2
pkgs that look like they should be upgraded:
Fetched 0 B in 0s
fetch.run() result: 0
blacklist: []
whitelist: []
No packages found that can be upgraded unattended and no pending auto-removals

啟用防火牆

不少雲端基礎服務商,如DigitalOcean, 都有提供雲端防火牆,如果是多台主機的情況下,使用雲端防火牆比較方便。以本文的單一主機來說,直接使用 Ubuntu 內建的 ufw 來提供簡易主機防火牆。

ufw allow 80
ufw allow 443
ufw allow ssh
ufw enable

其中,假如 SSH 服務的監聽埠不是預設的 22 的話,要把 ssh 改成對應的埠號。

注意: 不開啟 NodeBB 的 4567, 這個只允許從本機(localhost)連線

資料庫安裝 (Redis)

直接安裝系統預設的 Redis 套件,使用下列指令安裝:

$ sudo apt-get install -y redis-server

安裝後,為了讓 Redis 服務開機時自動啟動需要執行下列指令:

$ sudo systemctl enable redis.service

Redis 是作為 NodeBB 的主資料庫,所以資料持久性(persistence)需要特別設定以減少系統不正常當機時資料遺失的風險。為了這個目的,啟用 Redis 的 append-only log,底下是 append-only log 以及幾個相關的設定值(檔案 /etc/redis/redis.conf):

daemonize yes
supervised systemd
requirepass dsfjklewreriier    # redis 客戶端連線密碼,請不要直接套用,讀者需自訂。
appendonly yes

讀者需要將設定項目改成對應的設定值。

設定修改完成後,使用下列指令重啟 Redis:

$ sudo systemctl restart redis.service

Redis 安裝可參考 如何在 Ubuntu 18.04 上安裝和配置 Redis ⎘ 。

Web 安全憑證 (Let’s Encrypt)

Web 伺服器憑證是伺服器域名的身分證明,需要向一個 CA 組織申請核發,Let’s Encrypt 是個免費且受歡迎的 CA。 由於 Let’s Encrypt 已經支援 wildcard 域名憑證,本文使用 DNS 認證機制來申請 wildcard 憑證。

參考下列文章安裝 certbot 進行申請憑證:

因為希望憑證同時支援裸域名(developers.tw)以及子域名(*.developers.tw),申請指令要稍微修改

sudo certbot --server https://acme-v02.api.letsencrypt.org/directory -d *.developers.tw -d developers.tw --manual --preferred-challenges dns-01 certonly

按照畫面指示新增指定名稱的 DNS TXT 紀錄並進行驗證,如通過憑證檔案位於 /etc/letsencrpyt 目錄。

Web 服務 (Nginx)

Web 服務有下列目的:

  • 作為 NodeBB 負載均衡器(load balancer)。
  • 支援 TLS/SSL 網路加密結定。
  • 服務 NodeBB 靜態檔案資源。

#Developers.TW 使用 Nginx 作為 web 服務軟體。

安裝 Nginx 套件

$ sudo apt-get install -y nginx

設定 Nginx

本文的安裝,NodeBB 服務只接受本地(127.0.0.1)連線,監聽埠是 4567。底下將 Nginx 設為 NodeBB 服務的代理伺服器。

新增 /etc/nginx/sites-available/developers.tw,檔案內容如下:

upstream backend {
  server 127.0.0.1:4567;
}

server {
  listen 80;

  access_log  off;
  error_log   off;

  server_name developers.tw www.developers.tw;

  return 301 https://developers.tw$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;

  access_log  off;
  error_log   off;

  server_name www.developers.tw;

  ssl on;
  ssl_certificate /etc/letsencrypt/live/developers.tw/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/developers.tw/privkey.pem; # managed by Certbot

  return 301 https://developers.tw$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  error_log /var/log/nginx/developers.tw-error.log;
  access_log /var/log/nginx/developers.tw-access.log;

  server_name developers.tw;

  root /opt/nodebb/public;
  index index.html;

  gzip            on;
  gzip_min_length 1000;
  gzip_proxied    off;
  gzip_types      text/plain application/xml text/javascript application/javascript application/x-javascript text/css application/json;


  ssl on;
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_certificate /etc/letsencrypt/live/developers.tw/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/developers.tw/privkey.pem; # managed by Certbot
  ssl_protocols TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_session_cache shared:SSL:10m;

  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;
  proxy_set_header Host $http_host;
  proxy_set_header X-NginX-Proxy true;

  proxy_redirect off;

  # Socket.IO Support
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";


  location @backend {
        proxy_pass http://backend;
  }

  location ~ ^/assets/(.*) {
    root /opt/nodebb/;
    try_files /build/public/$1 /public/$1 @backend;
  }

  location /plugins/ {
    root /opt/nodebb/build/public/;
    try_files $uri @backend;
  }


location / {
  proxy_pass http://backend;
}
}

同樣地,developers.tw 需要更換為論壇實際使用的域名。 除了來自 NodeBB 官方文件的建議設定外,也設定了強制將 www.developers.tw 轉址為 developers.tw,且 http 協定轉成 `https’,也就是說: 只接受 HTTPS 連線。

啟用 NodeBB 的站點

$ sudo ln -s /etc/nginx/sites-available/developers.tw /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl restart nginx

到這個步驟,沒問題的話可以使用瀏覽器連線到 https://developers.tw ⎘ , 但因為後端的 NodeBB 還沒啟用,網頁會出現 503 錯誤。

執行環境安裝 (NodeJS)

NodeJS 以及 NodeBB 的安裝都是參考這篇文章 How To: Install NodeBB on DigitalOcean/Ubuntu 18.04 ⎘ 。

使用下列指令安裝 NodeJS:

$ sudo curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
$ sudo apt update
$ sudo apt install nodejs -y

應用服務安裝(NodeBB)

新增 nodebb 帳戶

為了權限控管,NodeBB 服務使用 nodebb 帳戶執行。使用下列指令新增帳戶:

$ sudo adduser nodebb

複製 NodeBB 原始程式

$ cd /opt
$ sudo git clone https://github.com/NodeBB/NodeBB.git nodebb
$ sudo chown -R nodebb:nodebb ./nodebb
$ sudo su - nodebb

初始設定 NodeBB

$ cd /opt/nodebb
$ ./nodebb setup

./nodebb setup 會詢問一系列問題,除下列外其餘使用預設值:

項目設定值
urlhttps://developers.tw ⎘
database選擇 redis
redis password在資料庫安裝 (Redis) 章節中,requirepass 的設定值

url 需要根據實際的域名做修改,上面範例是 #Developers.TW 的域名。

讓 NodeBB 隨系統自動啟動

使用文字編輯器新增/修改檔案/etc/systemd/system/nodebb.service,內容為:

[Unit]
Description=NodeBB
Documentation=https://docs.nodebb.org
After=system.slice multi-user.target redis.service

[Service]
Type=forking
User=nodebb

StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=nodebb

WorkingDirectory=/opt/nodebb
ExecStart=/usr/bin/node loader.js
Restart=always

[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable nodebb.service
$ sudo systemctl start nodebb.service

啟動完成後,就可以開啟瀏覽器連到 https://developers.tw/admin ⎘ , 登入控制台進行 NodeBB 的管理與設定。

小結

經過冗長的來來回回步驟後,終於有個可以上線的部署環境。但有了基本部署環境,NodeBB 還要根據需要進行設定與客製化,這個才是重中之重。NodeBB 的設定可以參考 官方的文件 ⎘,而NodeBB 的進階功能,不少需要額外申請雲端服務(如 Facebook SSO)或者安裝軟體(如 Solr等),讀者可視目的來決定是否有需要。

Sampot (山姆鍋)

獨立軟體開發者,專長分散式系統、Web 應用與雲端服務架構。目前一人開發NT² Vault:結構化數位資產保管箱。工作之餘關注開源軟體的發展與應用,偶爾在這裡碎念與分享。