Alpine Linux 是我們提供的最小映像。在我們的伺服器上,全新的 Alpine 3.21 閒置時使用 55 MB 記憶體和 153 MB 磁碟,而 Ubuntu 24.04 是 313 MB 和 2.7 GB。代價是放棄熟悉的工具。Alpine 用 apk 取代 apt,用 doas 取代 sudo,用 OpenRC 取代 systemd,用 musl 取代 glibc。
以下步驟與在 Debian 或 Ubuntu 上的前十分鐘相同,只是換成 Alpine 的做法。發布前,我們在自己的 Alpine 3.21 映像上執行了每一個指令,其中有兩個第一次就讓我們踩了坑。請用控制台中的密碼以 root 登入。
1. 更新,然後重新開機一次
apk update && apk upgrade
uname -r
ls /lib/modules
伺服器在第一次開機時已經安裝了可用的更新,所以 apk upgrade 通常沒剩多少事。重點看最後兩行。如果那次首次開機更新帶來了新核心,正在執行的核心(uname -r)在磁碟上就已經沒有對應的模組。任何需要載入模組的操作都會失敗,直到重新開機為止。在我們的測試伺服器上,安裝防火牆時輸出了 ERROR: Couldn't determine iptables version。如果兩個版本不同,現在就重新開機:
reboot
我們的測試伺服器不到一分鐘就回來了。
2. 建立能登入的使用者
adduser -D deploy
passwd deploy
adduser deploy wheel
不要略過 passwd。adduser -D 建立的帳號沒有密碼,Alpine 會把它標示為鎖定,而 sshd 會拒絕鎖定的帳號,即使金鑰正確。在我們的測試中,唯一的線索是 /var/log/messages 裡的這一行:
User deploy not allowed because account is locked
密碼之後也會用到:doas 要的就是它。
如果下單時加入了 SSH 金鑰,它就在 root 的 authorized_keys 裡。把它複製給新使用者:
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
install -m 600 -o deploy -g deploy /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
還沒有金鑰?在自己的電腦上產生一組,把公開金鑰貼到 /home/deploy/.ssh/authorized_keys。
3. 讓 doas 要求輸入密碼
Alpine 用 doas 取代 sudo,我們的映像已經允許 wheel 群組使用它。/etc/doas.d/wheel.conf 裡的規則是 permit nopass :wheel,也就是 wheel 群組的任何成員不必輸入任何東西就能成為 root。改成要求輸入密碼,並在幾分鐘內記住它:
echo 'permit persist :wheel' > /etc/doas.d/wheel.conf
從現在起,doas apk add nano 的用法就和 Ubuntu 上的 sudo apt install nano 一樣。
4. SSH:只用金鑰,禁止 root
sshd 依檔名順序讀取 /etc/ssh/sshd_config.d/ 裡的檔案,每項設定採用它找到的第一個值。在我們的映像中,第一個檔案是 00-eqvps.conf,它允許 root 與密碼登入,方便你第一天進入伺服器。取代它的內容:
cat > /etc/ssh/sshd_config.d/00-eqvps.conf <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
EOF
sshd -t && rc-service sshd restart
sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication) '
第三行在 Alpine 上很重要。映像使用帶 PAM 的 OpenSSH 版本,只寫前兩行時,我們的測試伺服器仍然提供 keyboard-interactive 登入。三行都寫上之後,不帶金鑰的登入嘗試會得到:
Permission denied (publickey).
保持 root 工作階段不要關閉。在第二個終端機中確認 ssh deploy@YOUR.SERVER.IP 能登入(NAT 方案要加上 -p 和控制台中的專屬連接埠),並確認 doas id 接受密碼。
5. 防火牆:ufw
ufw 在 community 套件庫中,我們的映像已經啟用這個套件庫:
apk add ufw
ufw limit 22/tcp
ufw --force enable
rc-update add ufw default
ufw status
limit 允許 SSH,但會拖慢連續開啟大量連線的一方。這裡 rc-update 很重要,因為如果沒把防火牆加入 runlevel,OpenRC 重新開機後不會啟動它。重新開機後,我們的伺服器回來時顯示 Status: active。在 NAT 方案上,請讓 SSH 留在 22 連接埠:你的專屬外部連接埠會轉送到伺服器內部的 22。在具獨立 IPv4 的方案上,需要時再開放網頁連接埠(ufw allow 80/tcp、ufw allow 443/tcp)。其餘內容請見 ufw 指南。
6. 開啟 cron 與每日更新
全新的 Alpine 伺服器完全沒有執行 cron。把它打開:
rc-update add crond default
rc-service crond start
Alpine 中 root 的 crontab 已經會在每天 02:00 執行 /etc/periodic/daily 裡的所有內容。把更新指令碼放進去:
cat > /etc/periodic/daily/apk-upgrade <<'EOF'
#!/bin/sh
apk upgrade --update-cache --no-progress >> /var/log/apk-auto.log 2>&1
EOF
chmod +x /etc/periodic/daily/apk-upgrade
run-parts --test /etc/periodic/daily
最後一個指令會列出 cron 將執行的指令碼,你的指令碼應該在清單中。這樣你就能持續取得 3.21 的修正。升級到下一個 Alpine 版本是另一個需要手動進行的步驟。核心更新仍然需要重新開機:偶爾重複第 1 步的 uname -r / ls /lib/modules 檢查。
7. 一張表看懂 OpenRC
如果你熟悉 systemd,改變的大致就是這些:
| 工作 | systemd | Alpine (OpenRC) |
|---|---|---|
| 啟動服務 | systemctl start nginx | rc-service nginx start |
| 開機自動啟動 | systemctl enable nginx | rc-update add nginx default |
| 狀態 | systemctl status nginx | rc-service nginx status |
| 正在執行的服務 | systemctl list-units | rc-status |
| 系統日誌 | journalctl | /var/log/messages |
8. Docker,以及 ufw 擋不住的連接埠
Alpine 很適合當 Docker 主機,因為系統本身幾乎不礙事:
apk add docker docker-cli-compose
rc-update add docker default
rc-service docker start
docker run --rm hello-world
在我們的伺服器上,連同下載共花了 12 秒。Docker 背景程式執行後,已用記憶體從 57 MB 增加到 124 MB。
有一個陷阱並非 Alpine 獨有:Docker 會寫入自己的防火牆規則。在 ufw 只允許 SSH 的情況下,我們用 -p 8080:80 啟動 nginx,結果從伺服器外部透過 8080 連接埠存取到了它。ufw 沒有擋下。如果某個容器只應透過同一台伺服器上的反向代理存取,請把它發布在 localhost:
docker run -d -p 127.0.0.1:8080:80 nginx:alpine
選哪個方案
Alpine 幾乎把全部記憶體留給你自己的軟體。Nano 方案(2 vCPU、1 GB、15 GB,$3/月)足以執行一個小服務或幾個容器。這是 NAT 方案,SSH 透過專屬連接埠進入。如果需要對網際網路開放 80 和 443 連接埠,Nano-IP 具獨立 IPv4,$8/月。較重的 Docker 堆疊可以選 Micro,2 GB,$5/月。
Alpine 3.21 位於 Alpine VPS 頁面,所有 VPS Linux 方案都可選。付款方式為 Base、Ethereum 或 Polygon 網路上的 USDT、USDC 或 ETH,不需證件,也不需信用卡。
評論
目前還沒有評論。歡迎成為第一位。