我的 VPS 服務器
Created: 10/12/2025 Updated: 10/21/2025
前言
在前文 我的個人頂級域名 (TLD) 中,我提及到我購買了 inogai.com。如今,是時候用它來幹點甚麼了。
甚麼是 VPS
Virtual Private Server (VPS) 是一種可以購買的伺服器服務。服務商通過虛擬化技術,將一台物理伺服器劃分成多個虛擬伺服器,然後出租給不同的用户。
一般而言,VPS 會有一個獨立的 IP 位址。用户可以通過這個 IP 位址存取服務器的資源。 IP 位址可以通過 DNS 綁定到域名上,這樣就可以像我的擁有的 inogai.com 一樣,通過域名來存取服務器。
作業系統(OS)選擇
適合應用於 VPS 的作業系統有很多種,不過,一般而言,諸多 Linux 發行版是最常見的選擇。理論上而言,Windows 也可以安裝在 VPS 上,不過,Windows 需要額外的授權費用,需求的資源較高,本身也不適合用於伺服器環境。
挑選一個適合的 Linux 發行版,通常會考慮以下幾個因素:
- 性能:輕量化的發行版能夠節省計算資源和儲存空間。
- 穩定性:伺服器需要長時間穩定運行,而且存在惡意存取的風險。
- 兼容性:選擇一個與應用程式和服務相容的發行版。
常見的選擇有:
Debian
- LTS 版本提供長期支援,適合伺服器環境。
- 有較多的資源和教程。
RHEL 系
Red Hat Enterprise Linux (RHEL) 是由 Red Hat 公司開發的企業級 Linux 發行版。對於個人而言,沒必要購買 RHEL 的支援,也可以享受 RHEL 的軟體生態。
CentOS 曾是由 Red Hat 贊助的社群版 RHEL 發行版,利用 RHEL 的開源源碼來構建。2020 年,Red Hat 宣佈 CentOS 不再定期更新,改為 CentOS Stream,這是一個滾動更新的發行版。
CentOS 終止支援後,Rocky Linux 和 AlmaLinux 是常見的替代選擇。
- 與 RHEL 相容,穩定性高。
- 有不錯的社群支援。
NixOS
NixOS 是一個較為特別 Linux 發行版,採用 Nix 套件管理系統。NixOS 的設計理念是 Reproducible 和 Declarative。系統的配置和構建都通過 Nix 表達式來描述,這樣可以保證系統的一致性和可重現性。
不過,由於 NixOS 的設計原因,軟件包會佔用較多的磁碟空間,而且也與其他 Linux 發行版不相容。構建軟件包的過程也較慢。有較陡峭的學習曲線,不適合新手。
Alpine Linux
輕量化的 Linux 發行版,適合資源有限的環境。Alpine 使用 musl libc 和 busybox,而非 glibc 和 GNU core utilities,這使得它的體積非常小,但也與其他 Linux 發行版不相容,需要另外編譯軟件包。適合用於容器化環境,如 Docker。
Docker
事實上,選擇哪一個 Linux 發行版並不是那麼重要。通過 Docker 我們可以在任意 Linux
發行版上運行應用程式,而不需要擔心相容性問題。即使在 Windows 或 Mac 上,我們也可以通過兼容層或虛擬化技術,例如 WSL2 和 Colima,來運行 Docker,不過這裏不作展開。
Docker Compose
Docker Compose 是一個用於定義和運行多容器 Docker 應用程式的工具。通過
docker-compose.yml 文件,我們可以定義應用程式的服務、網絡和卷等配置,使得我們的 docker 配置更 reproducible 和易於管理。
實操:一步步配置你的 VPS
前置需求
- 一台已購買並啟用的 VPS,並獲得 IP 位址和登入憑證。
- 基本的命令行操作知識。
- 在本地安裝好 SSH 客戶端。
瞭解了這些基礎知識後,我們就可以開始動手配置 VPS 了。本節將引導你完成從首次登入到部署第一個應用程式的完整流程。我選擇了 AlmaLinux 9 作為作業系統,並使用 Docker 和 Docker Compose 來管理服務。
為了方便起見,本文中的命令行指令會使用以下約定:
<arg>代表需要你替換成實際的參數,例如<ip-address>代表你的 VPS 的 IP 位址。[arg]代表可選參數- 在有
$的代碼塊,這代表這行是你需要輸入的指令,不需要輸入$符號。而沒有$的行代表輸出的結果。
步驟一:首次登入與系統更新
當你獲得 VPS 後,服務商會提供 IP 位址和 root 密碼。首先,我們以 root 身份登入伺服器。
如果你使用密碼登入,請務必設置一個強密碼,並在後續步驟中禁用密碼登入以增強安全性。很多壞人會掃端口撞密碼。
一服務商會在創建 VPS 時要求你上傳 SSH 公鑰,你可以用 ssh-keygen -t ed25519 生成一對 SSH 金鑰,然後把 $HOME/.ssh/id_ed25519.pub 通過用户界面上傳到伺服器。
默認而言,SSH 服務會在 22 端口上運行。為了安全起見,部分服務商會修改默認端口,請確保在連接時指定正確的端口。
如果你的 SSH 端口不是默認的 22,或你準備更改 SSH 端口,請務必在防火牆中開放相應的端口,否則你可能會被鎖在伺服器外!
在修改完成後,請務必不要退出當前的 SSH 連接。先打開一個新的終端窗口,確認你仍然可以通過 SSH 登入。
# 將 <ip-address> 和 <port> 替換為你的 VPS 資訊
ssh root@<ip-address> -p <port>
首次登入系統後,第一件事是更新系統的所有軟件包,確保系統處於最新狀態,包含最新的安全補丁。這也有益於兼容性。
sudo dnf upgrade
步驟二:基礎伺服器安全強化
直接使用 root 帳號進行日常操作是危險的。接下來,我們將創建一個新的個人帳號,並配置基礎的防火牆和 SSH 安全設置。
root 帳號是不安全的?使用 root 帳號意味著擁有系統的最高權限,你運行的程序將擁有完全的系統控制權,如修改防火牆設置、安裝或刪除軟件包等。如果你的 root 帳號被攻擊者入侵,整個系統將面臨極大的風險。相反,使用通戶帳號進行日常操作,並僅在必要時使用 sudo 提升權限,可以大大降低安全風險。
1. 創建新用戶
我們來創建一個名為 dev 的新用戶(你可以替換成你喜歡的用戶名),並賦予其 sudo
權限。
創建新用戶後,請務必使用 passwd 命令為其設置強密碼。
在不同的 Linux 發行版中,sudo 群組可能名稱不同;用户管理指令也可能會有所差異。例如,在基於 Debian 的系統中,通常是 sudo 群組,而在基於 RHEL 的系統中,則是 wheel 群組。請根據你的發行版選擇正確的群組名稱。這裏我們以基於 RHEL 的
AlmaLinux 為例,使用 wheel 群組。
# 創建新用戶
adduser dev
# 為新用戶設置密碼(請使用高強度密碼)
passwd dev
# 將用戶添加到 `wheel` 群組,使其能使用 sudo
usermod -aG wheel dev
2. 配置 SSH 金鑰認證
為了安全,我們應該禁用密碼登入,改用更安全的 SSH 金鑰。
首先,在 你的本機 上生成一對 SSH 金鑰。如果已有金鑰,可以跳過此步。
選擇金鑰類型
ed25519 是目前推薦的金鑰類型,因為它在同等安全性下性能更好。如果你的系統不支持 ed25519,可以使用 RSA,但建議使用至少 4096 位的 RSA 金鑰。
ssh-keygen -t rsa -b 4096
# 這會在 ~/.ssh/ 目錄下生成 id_ed25519 (私鑰) 和 id_ed25519.pub (公鑰)
ssh-keygen -t ed25519
接著,將你的公鑰複製到伺服器上剛創建的 dev 帳號中。
# 將公鑰複製到伺服器,推薦使用 ssh-copy-id
ssh-copy-id -p <port> dev@<ip-address>
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
dev@<ip-address>'s password: # 輸入你剛設置的 dev 用戶密碼
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -p <port> 'dev@<ip-address>'"
and check to make sure that only the key(s) you wanted were added.
完成後,嘗試用新用戶身份登入,這次應該不需要輸入密碼。
ssh -p <port> dev@<ip-address>
3. 強化 SSH 伺服器安全
修改配置後,在斷開當前連線前,請務必打開一個新的終端窗口,確認你仍然可以透過
dev 用戶成功登入。否則,你可能會被鎖在伺服器外!
成功透過金鑰登入後,我們就可以禁用 root 登入和密碼認證來加固伺服器。
在伺服器上編輯 SSH 配置文件 /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
找到並修改以下幾行:
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
man 指令不同環境 OS 和版本下,sshd_config 文件的配置可能會有所不同。你可以使用
man sshd_config 指令來查閱當前系統的配置說明。這樣可以幫助你理解每個配置項的作用,並根據需要進行調整。
為甚麼要這樣設置?
在現代 OpenSSH 中,只需設置 AuthenticationMethods publickey 即可。前兩項是舊版的配置方式,加上是為了向下兼容。在兩者都設置了的情況下,只有第三行會生效。
PasswordAuthentication no: 禁用傳統的密碼登入方式。KbdInteractiveAuthentication no: 禁用鍵盤互動式認證,這也可能被用作密碼登入的一種形式。AuthenticationMethods publickey: 最重要的一行!這明確指定了 只允許 使用公鑰進行認證。
透過這三項設置,我們徹底關閉了所有基於密碼的登入途徑,只留下更安全的 SSH 金鑰認證,極大地提升了伺服器的安全性。
保存文件後,重啟 SSH 服務使配置生效:
sudo systemctl restart sshd
你已經為 root 和 dev 用戶配置了 SSH 金鑰登入,如何驗證你禁用了密碼登入?你可以使用一個不存在的賬户名稱試圖登入。伺服器會拒絕這次登入,並顯示類似以下的錯誤訊息。
$ ssh notauser@<ip-address> -p <port>
notauser@<ip-address>: Permission denied (publickey).
4. 配置防火牆
更新於 2025-10-21:然而,Docker 會直接覆寫 iptables,並不遵循防火牆規則。如果你不特別指定的話,Docker 將會把暴露的端口綁定到 0.0.0.0,也就是所有網絡接口,這在 VPS 上通常等於公開訪問。可以參閲以下鏈接:https://holywhite.com/archives/489
與鏈接文章介紹的配置不同,我建議你只通過一個反向代理(如 Nginx)來暴露 80/443 端口。其他服務則通過 Docker Compose 的內部網絡來通信,而不直接暴露端口到外網。
如果有時間的話,我會在後續的文章中介紹 Swag(Secure Web Application Gateway) 作為 Reversed Proxy 的配置。到時候我會把鏈接放在這裏。
在配置防火牆時,請務必確保允許 ssh 端口(默認為 22,或你自定義的端口),以免被鎖在伺服器外!
firewalld 默認允許 22 端口,但如果你更改了 ssh 端口,或服務商已經更改了端口,請務必在防火牆中開放相應的端口。
如果你不確定防火牆的配置,請在修改前備份當前配置。在修改後,不要殺死當前進程,務必先打開一個新的終端,確認你仍然可以通過 ssh 登入。
AlmaLinux 默認使用 firewalld 作為防火牆管理工具。我們來確保防火牆已啟用,並允許 SSH 連接。
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
firewalld 使用區域(zone)來管理不同的網絡接口和服務。默認區域通常是 public。
zone 代表一組網絡來源。 public 就是來自公共網絡的連接。
每個 zone 都有一組預定義的服務和端口規則。你可以使用 firewall-cmd 指令來查看和修改這些規則。在服務器上,我們通常應該只用到 public 區域。
# 查看當前區域
$ sudo firewall-cmd --get-active-zones
public
interfaces: eth0 eth1
$ sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work
$ sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0 eth1
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
從上面的輸出可以看到,firewalld 默認允許了 ssh 服務(對應 22 端口)。如果你更改了 SSH 端口,或者需要為其他服務(如 HTTP/HTTPS)開放端口,就需要手動添加規則。
例如,假設我們將 SSH 端口改為 22022,我們需要執行以下指令來開放此端口:
# 將 22022/tcp 端口永久添加到 public 區域
sudo firewall-cmd --zone=public --add-port=22022/tcp --permanent
--add-port=22022/tcp:指定要開放的端口號和協議(TCP)。--permanent:將此規則設為永久性。如果沒有這個參數,規則會在防火牆重啟後失效。
現在,我們重新載入防火牆,並再次檢查規則列表,確認新端口已成功添加。
$ sudo systemctl restart firewalld
$ sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0 eth1
sources:
services: cockpit dhcpv6-client ssh
ports: 22022/tcp
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
步驟三:安裝 Docker 與 Docker Compose
完成基礎安全設置後,我們來安裝容器化工具。
# 1. 解除安裝可能已存在的舊版本
sudo dnf remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
# 2. 添加 Docker 的官方軟件源
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 3. 安裝 Docker 相關軟件包
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 4. 啟動並設置 Docker 開機自啟
sudo systemctl enable --now docker
# 5. (可選) 將你的用戶添加到 docker 群組,這樣執行 docker 指令時就不用加 sudo
sudo usermod -aG docker dev
# 添加後,你需要登出再重新登入,以使群組變更生效
exit
重新登入後,執行 docker ps 驗證安裝是否成功,以及是否無需 sudo。重新登入後,我們可以運行一個簡單的測試指令來驗證 Docker 是否安裝成功並正常運作。
docker run 指令會根據指定的 鏡像 (Image) 來啟動一個 容器 (Container)。
- 鏡像 (Image):一個唯讀的模板,打包了應用程式運行所需的一切(程式碼、函式庫、配置)。打包者通過
Dockerfile來定義鏡像的內容和構建過程。Image 就像編譯好的應用程式,隨時可以用來啟動容器。 - 容器 (Container):鏡像的運行實例。
讓我們運行 hello-world 鏡像:
docker run hello-world
docker run 指令會自動從遠端倉庫拉取鏡像,如果本地沒有的話。這個過程類似於下下載應用程式安裝包,然後啟動應用程式。
然後,會自動創建並啟動一個容器,然後在容器內運行指定的命令。在這個例子中,hello-world 鏡像的默認命令是打印一條歡迎訊息,然後容器會自動退出。
拉完屎記得擦屁股
你可以用 docker ps 查看正在運行的容器,用 docker ps -a 查看所有容器(包含已停止的)。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
131a1f11fa6f hello-world "/hello" 10 seconds ago Exited (0) 5 seconds ago flamboyant_solomon
你會發現 NAMES 欄位顯示了一個隨機生成的名稱(例如 flamboyant_solomon)。這是 Docker 自動分配的。如果你想指定一個易於識別的名稱,可以在 docker run 指令中加上用 --name <container-name> 參數指定容器
當你不需要這個鏡像時,用 docker rm flamboyant_solomon 或
docker rm 131a1f11fa6f 刪除容器。
用 docker image ls 查看本地的鏡像列表。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 1b44b5a3e06a 2 months ago 10.1kB
用 docker rmi hello-world 或 docker rmi 1b44b5a3e06a 刪除鏡像。你也可以
docker image prune 刪除所有沒有對應容器的鏡像。
由於是首次運行,Docker 在本地找不到 hello-world 鏡像,於是會自動從 Docker
Hub(官方的鏡像倉庫)下載它,然後啟動容器。你會看到類似以下的輸出:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
...
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
這段輸出確認了兩件事:
- Docker 能夠成功從遠端倉庫拉取鏡像。
- Docker 能夠根據鏡像成功運行一個容器。
看到 “Hello from Docker!” 的訊息,就代表你的 Docker 環境已經準備就緒了!
步驟四:使用 Docker Compose 部署應用
直接使用 docker run 指令來啟動容器雖然可行,但參數繁多,不易管理。Docker
Compose 讓我們可以透過一個 docker-compose.yml 文件來聲明式定義和管理多容器應用。
以下是一個運行 Nginx 網頁伺服器的簡單範例。
首先,創建一個項目目錄並進入:
mkdir my-nginx-app; cd my-nginx-app
創建一個 docker-compose.yml 文件:
nano docker-compose.yml
貼上以下內容:
services:
web:
image: nginx:latest
container_name: my-nginx-container
ports:
- "8080:80"
volumes:
- ./nginx-content:/usr/share/nginx/html:ro
restart: unless-stopped
對應的 docker 指令是:
docker run -d \
--name web \
-p 8080:80 \
-v $(pwd)/nginx-content:/usr/share/nginx/html:ro \
--restart unless-stopped \
nginx:latest
這個文件定義了一個名為 web 的服務,它使用最新的 nginx 鏡像。讓我們來逐一解析:
services:docker-compose.yml的頂層鍵,所有服務都在其下定義。web: 我們自定義的服務名稱。image: nginx:latest: 指定服務使用的 Docker 鏡像。這裏我們使用 Docker Hub 上的官方最新版 Nginx。container_name: my-nginx-container: 為容器指定一個易於識別的名稱。ports: 將主機的端口映射到容器的端口。"8080:80"表示將主機的 8080 端口映射到容器的 80 端口。volumes: 將主機的目錄掛載到容器中。./nginx-content:/usr/share/nginx/html:ro表示將當前目錄下的nginx-content文件夾以**唯讀(ro)**模式掛載到 Nginx 存放網站內容的默認位置。restart: unless-stopped: 定義容器的重啟策略。unless-stopped表示除非手動停止,否則容器在退出時會自動重啟,有助於確保服務的持續可用性。
為了讓 Nginx 能顯示內容,我們還需要創建 nginx-content 目錄和一個首頁文件。
mkdir nginx-content
echo '<h1>Hello from my VPS</h1>' > nginx-content/index.html
現在,你的目錄結構應該是:
my-nginx-app/
├── docker-compose.yml
└── nginx-content/
└── index.html
一切就緒!使用 docker compose 指令啟動服務:
# -d 表示在後台 (detached) 運行
docker compose up -d
Docker 會自動下載 Nginx 鏡像並啟動容器。現在,打開你的瀏覽器,訪問˙
http://<ip-address>:8080,你將會看到 “Hello from my VPS” 的頁面。
![[Pasted image 20251012191947.png]]
管理你的應用
以下是一些常用的 Docker Compose 指令:
docker compose down: 停止並移除由up創建的容器和網絡,與up一樣,也需要在同一個目錄下運行。docker compose ps: 列出當前 Compose 項目管理的所有容器狀態。docker compose logs -f web:-f代表 follow。持續追蹤web服務的日誌輸出。docker compose exec web bash: 在web服務的容器中啟動一個bashshell,可以在容器內執行命令,方便調試。
總結
掌握了以上內容,我們在 VPS 上部署各種各樣的服務就變得輕而易舉了。無論是運行個人網站、博客,還是搭建私人雲存儲或其他應用只要找到對應的 Docker 鏡像,通過 Docker Compose 定義好配置,就能快速部署。
如果有機會,我會分享一些我在 VPS 上部署的服務和經歷,例如 Secure Web Application Gateway。它是一個集成了 Nginx、SSL/TLS 憑證和多種實用功能的 Docker 鏡像,非常適合用於保護和管理多個網頁應用。