在現代 Web 基礎架構中,單一伺服器同時託管多個應用程式已成為資源優化與成本控制的標準實踐。透過適當的架構設計與組態管理,我們能夠在同一台實體或虛擬主機上運行內容管理系統、私有雲端儲存、協作平台等多種服務,同時維持良好的效能與安全性。這種整合式部署方式不僅降低了硬體成本與管理複雜度,也提供了統一的監控與維護介面。
NGINX 作為高效能的 Web 伺服器與反向代理解決方案,特別適合這類多應用程式託管環境。相較於傳統的 Apache HTTP Server,NGINX 採用事件驅動的非同步架構,能夠以更少的記憶體資源處理大量並發連線。其強大的反向代理功能讓我們能夠在單一網路介面上整合多個後端服務,透過虛擬主機與路徑路由實現流量分發。同時,NGINX 對靜態內容的高速處理能力,搭配適當的快取策略,能夠顯著提升整體系統效能。
本文將深入探討如何在 NGINX 伺服器上部署兩個重要的開源應用程式。WordPress 作為全球最廣泛使用的內容管理系統,為數億個網站提供動態內容發布能力,其豐富的外掛生態系統與主題市場讓使用者能夠快速建立各類型的網站。Nextcloud 則是領先的私有雲端儲存解決方案,提供檔案同步、協作編輯、行事曆管理、聯絡人同步等完整的生產力工具套件,讓組織能夠在自己的基礎設施上建立資料主權。
我們將採用混合的部署策略,WordPress 直接運行在主機環境中,搭配 PHP-FPM 處理動態內容,而 Nextcloud 則使用 Docker 容器化技術部署,透過 NGINX 反向代理整合。這種混合架構充分發揮了兩種部署模式的優勢,WordPress 獲得更直接的檔案系統存取與更簡單的組態管理,Nextcloud 則享有容器化帶來的隔離性、可攜性與快速部署能力。整個過程涵蓋 MySQL 資料庫組態、NGINX 效能調校、SSL/TLS 憑證整合、Docker 容器編排與反向代理架構設計,最終建立一個安全、穩定且高效能的多應用程式託管平台。
WordPress 完整部署流程與組態最佳化
WordPress 的成功部署需要妥善處理多個相互依賴的元件,包括資料庫系統、Web 伺服器、PHP 執行環境以及應用程式本身。每個環節的組態都會影響最終系統的效能、安全性與穩定性。我們將從資料層開始,逐步建立完整的 WordPress 執行環境。
MySQL 資料庫環境建置
資料庫是 WordPress 的核心儲存層,負責保存所有的內容、使用者資訊、組態設定與外掛資料。正確的資料庫組態不僅確保資料的安全性,也直接影響網站的回應速度。在開始安裝 WordPress 之前,我們需要先建立專用的資料庫與使用者帳戶。
sudo mysql -u root -p
進入 MySQL 命令列介面後,我們將執行一系列的資料庫操作。首先建立 WordPress 專用的資料庫,使用 UTF-8 字元集確保能夠正確儲存多語言內容,包括中文、日文、表情符號等特殊字元。
CREATE DATABASE wordpress_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
這個指令建立了名為 wordpress_db 的資料庫,utf8mb4 字元集是 UTF-8 的完整實作,能夠儲存四位元組的字元,包括較新的 Unicode 字元與 Emoji 表情符號。utf8mb4_unicode_ci 排序規則提供了良好的多語言比對能力,適合國際化網站使用。
接下來建立專門用於 WordPress 的資料庫使用者,並授予必要的權限。基於安全性考量,應該避免使用 root 帳戶操作應用程式資料庫,而是建立具有最小必要權限的專用帳戶。
CREATE USER 'wordpress_user'@'localhost' IDENTIFIED BY 'strong_password_here';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX,
CREATE TEMPORARY TABLES, LOCK TABLES
ON wordpress_db.* TO 'wordpress_user'@'localhost';
FLUSH PRIVILEGES;
這個組態建立了只能從本機連線的使用者帳戶,並授予 WordPress 運作所需的所有資料庫權限。SELECT、INSERT、UPDATE、DELETE 是基本的資料操作權限,CREATE、DROP、ALTER 允許 WordPress 建立與修改資料表結構,這在安裝外掛或主題時經常需要。INDEX 權限讓 WordPress 能夠建立索引以優化查詢效能,CREATE TEMPORARY TABLES 與 LOCK TABLES 則用於複雜查詢的效能優化。
在設定密碼時,應該使用強密碼,包含大小寫字母、數字與特殊符號,長度至少十二個字元。可以使用密碼管理工具產生並儲存這個密碼,避免使用容易猜測的密碼。完成資料庫建立後,可以驗證設定是否正確。
SHOW DATABASES;
SELECT user, host FROM mysql.user WHERE user = 'wordpress_user';
EXIT;
這些查詢確認資料庫已成功建立,且使用者帳戶具有正確的存取限制。離開 MySQL 後,可以測試新建立的帳戶是否能夠正常連線。
mysql -u wordpress_user -p
USE wordpress_db;
SHOW TABLES;
EXIT;
此時資料庫應該是空的,沒有任何資料表,這是正常的狀態。WordPress 會在首次安裝時自動建立所需的資料表結構。
WordPress 核心檔案準備與權限設定
有了資料庫基礎後,下一步是準備 WordPress 的應用程式檔案。我們需要決定 WordPress 的安裝位置,建立適當的目錄結構,並設定正確的檔案權限以確保安全性。
sudo mkdir -p /var/www/wordpress
cd /var/www/wordpress
在伺服器上建立 WordPress 的安裝目錄,通常會選擇 /var/www 下的子目錄。接下來從 WordPress 官方網站下載最新的穩定版本。
sudo wget https://wordpress.org/latest.tar.gz
sudo tar -xzf latest.tar.gz
sudo mv wordpress/* .
sudo rm -rf wordpress latest.tar.gz
下載並解壓縮後,WordPress 的檔案會被放置在一個名為 wordpress 的子目錄中。我們將這些檔案移動到當前目錄的根層級,然後刪除空的子目錄與壓縮檔案,保持目錄結構的整潔。
檔案權限的設定是 WordPress 安全性的重要環節。不當的權限設定可能導致安全漏洞或功能異常。WordPress 需要能夠寫入特定的目錄以儲存上傳的檔案、快取資料與自動更新,但同時也要限制不必要的寫入權限以降低安全風險。
sudo useradd -r -s /bin/false wordpress
sudo chown -R wordpress:wordpress /var/www/wordpress
sudo find /var/www/wordpress -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress -type f -exec chmod 644 {} \;
這一系列指令完成了幾個重要的安全設定。首先建立一個專用的系統使用者 wordpress,這個使用者沒有登入 Shell 的能力,僅用於運行 Web 服務。接著將所有 WordPress 檔案的擁有者設定為這個使用者。
目錄權限設定為 755,代表擁有者可以讀取、寫入與執行,而群組與其他使用者只能讀取與執行。檔案權限設定為 644,代表擁有者可以讀寫,其他人只能讀取。這種權限配置在安全性與功能性之間取得了良好的平衡。
WordPress 的某些目錄需要額外的寫入權限,以便儲存使用者上傳的內容與系統產生的快取檔案。
sudo mkdir -p /var/www/wordpress/wp-content/uploads
sudo mkdir -p /var/www/wordpress/wp-content/cache
sudo chmod 775 /var/www/wordpress/wp-content/uploads
sudo chmod 775 /var/www/wordpress/wp-content/cache
uploads 目錄儲存使用者透過媒體庫上傳的圖片、影片與其他檔案。cache 目錄則用於快取外掛儲存暫時資料以提升效能。這兩個目錄需要 Web 伺服器能夠寫入,因此權限設定為 775,允許擁有者與群組成員寫入。
NGINX 伺服器核心組態
NGINX 的組態檔案採用階層式結構,從全域設定到虛擬主機的具體組態,每個層級都影響著 Web 伺服器的行為。我們將從主組態檔案開始,逐步建立完整的 WordPress 託管環境。
NGINX 的主組態檔案通常位於 /etc/nginx/nginx.conf,這個檔案定義了影響整個伺服器的全域設定。
user wordpress wordpress;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /var/run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8;
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log detailed buffer=32k flush=5s;
error_log /var/log/nginx/error.log warn;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
types_hash_max_size 2048;
server_names_hash_bucket_size 128;
client_max_body_size 64M;
client_body_buffer_size 128k;
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/rss+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
gzip_disable "msie6";
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
這個全域組態包含了多個重要的效能優化設定。worker_processes auto 讓 NGINX 根據 CPU 核心數自動決定工作程序數量,充分利用多核心處理器的運算能力。worker_connections 4096 定義每個工作程序能夠處理的最大並發連線數,配合 multi_accept 可以同時接受多個新連線,提升高流量情境下的效能。
sendfile 啟用了作業系統層級的零拷貝機制,在傳輸靜態檔案時繞過應用程式緩衝區,直接從檔案系統快取傳送到網路 Socket,大幅提升傳輸效率。tcp_nopush 與 tcp_nodelay 的組合優化了 TCP 封包的傳送策略,減少網路延遲。
Gzip 壓縮設定讓 NGINX 自動壓縮文字類型的回應內容,包括 HTML、CSS、JavaScript、JSON 等,能夠將傳輸量減少到原本的 20-30%,特別有利於行動網路與頻寬受限的使用者。壓縮等級設定為 6 是效能與壓縮率之間的良好平衡點,過高的壓縮等級會消耗過多 CPU 資源但壓縮率提升有限。
檔案快取設定啟用了 NGINX 的靜態檔案快取機制,將經常存取的檔案的後設資料保存在記憶體中,避免重複的檔案系統查詢操作。這個優化對於包含大量圖片與靜態資源的 WordPress 網站特別有效。
WordPress 虛擬主機組態
虛擬主機組態定義了 NGINX 如何處理特定網域的請求,包括 SSL 設定、請求路由、PHP 處理等關鍵邏輯。我們將建立兩個伺服器區塊,一個處理 HTTP 請求並重導向到 HTTPS,另一個處理實際的 HTTPS 流量。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream php_backend {
server unix:/var/run/php/php8.2-fpm.sock;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
root /var/www/wordpress;
index index.php index.html;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
client_max_body_size 128M;
client_body_timeout 60s;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
log_not_found off;
access_log off;
allow all;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php_backend;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 180s;
fastcgi_read_timeout 180s;
}
location ~ /\.(?!well-known) {
deny all;
}
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
}
這個組態包含了多層次的安全與效能優化。HTTP 伺服器區塊保留了 Let’s Encrypt 憑證驗證路徑,允許自動更新 SSL 憑證,其他所有請求都被重導向到 HTTPS,強制加密連線。
HTTPS 伺服器區塊的 SSL 設定遵循現代安全標準,只啟用 TLS 1.2 與 TLS 1.3 協定,禁用已知存在漏洞的舊版協定。加密套件選擇支援前向保密性的演算法,確保即使伺服器私鑰外洩,過去的加密通訊也無法被解密。
OCSP Stapling 啟用後,伺服器會定期從憑證頒發機構取得憑證狀態資訊並快取,在 TLS 握手時直接提供給客戶端,減少客戶端的額外查詢,加快連線建立速度。
安全標頭的設定增強了瀏覽器端的安全防護。Strict-Transport-Security 指示瀏覽器在接下來的兩年內只能透過 HTTPS 連線到這個網站。X-Frame-Options 防止網站被嵌入到其他網站的 iframe 中,避免點擊劫持攻擊。X-Content-Type-Options 防止瀏覽器嘗試猜測內容類型,降低 MIME 類型混淆攻擊的風險。
靜態資源的 location 區塊設定了長期快取,讓瀏覽器將這些不常變動的檔案快取一年,大幅減少重複請求。搭配 immutable 標記,瀏覽器在快取期間完全不會重新驗證這些檔案,進一步優化載入速度。
PHP 處理的 location 區塊使用 Unix Socket 連線到 PHP-FPM,相較於 TCP Socket 具有更低的延遲與更高的安全性。FastCGI 緩衝區設定經過調校,能夠處理較大的 PHP 回應而不需要寫入臨時檔案,提升動態頁面的產生速度。
安全相關的 location 區塊拒絕存取隱藏檔案與上傳目錄中的 PHP 檔案,這是防禦常見攻擊手法的重要措施。許多 WordPress 外掛存在上傳任意檔案的漏洞,攻擊者會嘗試上傳惡意的 PHP 腳本並執行,透過拒絕執行上傳目錄中的 PHP 檔案可以有效降低這類攻擊的風險。
儲存組態檔案後,需要建立符號連結啟用網站,並測試組態的正確性。
sudo ln -s /etc/nginx/sites-available/wordpress.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
NGINX 組態測試會檢查語法錯誤與基本的邏輯問題,確認無誤後才重新載入組態。這個過程不會中斷現有的連線,提供平滑的組態更新體驗。
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
start
:建立 MySQL 資料庫;
note right
建立專用資料庫與使用者
設定適當權限與字元集
end note
:下載 WordPress 核心檔案;
note right
從官方網站取得最新版本
解壓縮到目標目錄
end note
:設定檔案權限;
note right
建立專用系統使用者
設定目錄與檔案權限
確保上傳目錄可寫入
end note
:組態 NGINX 主設定;
note right
優化全域效能參數
啟用 Gzip 壓縮
設定檔案快取
end note
:建立虛擬主機組態;
partition "NGINX 虛擬主機設定" {
:設定 HTTP 到 HTTPS 重導向;
:組態 SSL/TLS 憑證與加密套件;
:定義靜態資源快取策略;
:設定 PHP-FPM 處理規則;
:加入安全防護標頭;
}
:測試並重新載入 NGINX;
note right
使用 nginx -t 驗證組態
無錯誤後重新載入服務
end note
:執行 WordPress 安裝程式;
partition "Web 介面安裝" {
:存取安裝頁面;
:輸入資料庫連線資訊;
:建立管理員帳戶;
:設定網站標題與描述;
}
:完成基本組態;
note right
設定永久連結結構
安裝必要外掛
選擇並啟用主題
end note
:WordPress 部署完成;
stop
@enduml
WordPress 安裝與初始組態
完成伺服器端的所有準備工作後,接下來透過 WordPress 的 Web 安裝介面完成最後的設定步驟。在瀏覽器中開啟網站的 URL,系統會自動引導到安裝頁面。
安裝程式首先要求提供資料庫連線資訊,這些資訊必須與我們在 MySQL 中建立的組態完全一致。
資料庫名稱填入 wordpress_db,使用者名稱填入 wordpress_user,密碼則是之前設定的強密碼。資料庫主機通常填入 localhost,因為 MySQL 與 WordPress 運行在同一台伺服器上。如果 MySQL 使用非標準埠,需要在主機名稱後加上埠號,例如 localhost:3307。資料表前綴預設為 wp_,在單一資料庫中安裝多個 WordPress 實例時可以使用不同的前綴區分。
提交資料庫資訊後,WordPress 會嘗試連線並建立組態檔案。如果連線成功,會進入網站資訊設定頁面,要求輸入網站標題、管理員使用者名稱、密碼與電子郵件地址。
網站標題會顯示在瀏覽器標籤與搜尋結果中,應該簡潔明確地描述網站內容。管理員使用者名稱不應該使用 admin 這類容易猜測的名稱,選擇獨特且不易猜測的名稱能夠提升安全性。密碼需要足夠強度,WordPress 會提供密碼強度指示器協助判斷。管理員電子郵件地址用於接收系統通知與密碼重設郵件,務必使用有效且經常檢查的信箱。
安裝完成後,可以登入 WordPress 後台開始進行進階組態。在設定選單中,永久連結結構是重要的 SEO 設定項目。預設的查詢字串格式如 ?p=123 對搜尋引擎與使用者都不友善,建議選擇文章名稱格式如 /sample-post/,或自訂格式如 /%year%/%monthnum%/%postname%/。
變更永久連結結構後,NGINX 的 try_files 指令會自動處理 URL 重寫,無需額外組態。這是 NGINX 相較於 Apache 的優勢之一,不需要複雜的 .htaccess 規則。
基本的安全加固措施包括停用檔案編輯功能,防止攻擊者透過後台直接修改主題與外掛的 PHP 檔案。在 wp-config.php 中加入以下設定。
define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true);
第一個設定禁用後台的檔案編輯器,第二個設定進一步禁止透過後台安裝或更新外掛與主題。雖然這會犧牲一些便利性,但能夠大幅降低帳戶被入侵後的損害範圍。
啟用自動更新功能,讓 WordPress 自動安裝安全性更新,確保系統維持在最新的安全狀態。
define('WP_AUTO_UPDATE_CORE', true);
add_filter('auto_update_plugin', '__return_true');
add_filter('auto_update_theme', '__return_true');
定期備份是資料安全的最後一道防線。可以使用外掛如 UpdraftPlus 設定自動備份,將備份檔案儲存到遠端的雲端儲存服務,確保即使伺服器完全損毀也能恢復網站。
Nextcloud 容器化部署與反向代理整合
Nextcloud 作為功能完整的私有雲端平台,其部署涉及多個相互依賴的服務元件,包括 Web 伺服器、PHP 執行環境、資料庫、Redis 快取、協作文件服務等。使用 Docker 容器化技術能夠大幅簡化這個複雜的部署流程,同時確保各元件之間的隔離性與可攜性。
Docker Compose 編排架構
Nextcloud 官方提供了 All-in-One 容器映像,將所有必要的服務打包在一起,透過內部的容器編排實現完整的 Nextcloud 部署。這個映像內建 Apache Web 伺服器,我們會將其配置為在非標準埠運行,透過 NGINX 反向代理對外提供服務。
首先建立 Nextcloud 的工作目錄並準備 Docker Compose 組態檔案。
sudo mkdir -p /opt/nextcloud
cd /opt/nextcloud
建立 docker-compose.yml 檔案,定義 Nextcloud 容器的完整組態。
version: '3.8'
services:
nextcloud-aio-mastercontainer:
image: nextcloud/all-in-one:latest
init: true
restart: unless-stopped
container_name: nextcloud-aio-mastercontainer
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:11000:11000"
environment:
- APACHE_PORT=11000
- APACHE_IP_BINDING=127.0.0.1
- SKIP_DOMAIN_VALIDATION=false
- NEXTCLOUD_DATADIR=/mnt/nextcloud-data
- NEXTCLOUD_MOUNT=/mnt/
- NEXTCLOUD_UPLOAD_LIMIT=10G
- NEXTCLOUD_MAX_TIME=3600
- NEXTCLOUD_MEMORY_LIMIT=512M
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.example.com
- TALK_PORT=3478
networks:
- nextcloud_network
volumes:
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainer
networks:
nextcloud_network:
name: nextcloud_network
driver: bridge
這個 Docker Compose 組態包含了多個重要的設定項目。容器映像使用 latest 標籤確保始終運行最新版本,雖然在生產環境中通常建議固定版本號以確保可重現性,但對於 All-in-One 映像,官方建議使用最新版本以獲得即時的安全更新與功能改進。
init: true 啟用 init 程序管理,確保容器內的程序能夠正確處理信號與殭屍程序。restart: unless-stopped 設定容器在失敗時自動重啟,但在手動停止後不會自動啟動,提供了良好的可用性與可控性平衡。
Volume 掛載包含兩個關鍵的綁定。nextcloud_aio_mastercontainer 命名卷儲存 Nextcloud 的組態資料,這個卷的資料會持久化保存,即使容器被刪除也不會遺失。/var/run/docker.sock 綁定讓 mastercontainer 能夠與主機的 Docker 引擎通訊,用於啟動與管理其他 Nextcloud 相關的容器,例如資料庫、Redis、協作服務等。
埠口綁定使用 127.0.0.1 限制只能從本機存取,外部流量必須透過 NGINX 反向代理才能到達 Nextcloud。埠口 8080 用於 All-in-One 的管理介面,埠口 11000 則是 Nextcloud 主應用程式的 Apache 服務。
環境變數組態定義了 Nextcloud 的運行參數。APACHE_PORT 與 APACHE_IP_BINDING 設定 Apache 監聽的埠口與網路介面。NEXTCLOUD_DATADIR 指定使用者資料的儲存路徑,這個路徑應該對應到足夠大且可靠的儲存空間。NEXTCLOUD_UPLOAD_LIMIT 設定單一檔案的上傳大小限制,這個值需要與 NGINX 的 client_max_body_size 協調一致。NEXTCLOUD_TRUSTED_DOMAINS 定義允許存取 Nextcloud 的網域名稱,這是重要的安全設定,防止 HTTP Host 標頭注入攻擊。
啟動 Nextcloud 容器前,確認 Docker 與 Docker Compose 已正確安裝。
docker --version
docker compose version
執行容器編排,啟動所有必要的服務。
sudo docker compose up -d
Docker Compose 會自動下載映像、建立網路與卷,然後啟動容器。這個過程可能需要幾分鐘,特別是首次執行時需要下載數 GB 的容器映像。可以透過日誌監控啟動過程。
sudo docker compose logs -f
觀察日誌輸出,確認 Nextcloud 容器成功啟動且沒有錯誤訊息。當看到 “AIO startup successful” 等訊息時,代表基礎容器已就緒。此時可以透過瀏覽器存取管理介面 http://localhost:8080,完成 Nextcloud 的初始設定。
管理介面會提供一組隨機產生的密碼,這個密碼用於登入 All-in-One 的管理面板。妥善保存這個密碼,後續管理 Nextcloud 時會需要。在管理介面中,設定外部網域名稱為 https://nextcloud.example.com,這是使用者實際存取 Nextcloud 的 URL。
NGINX 反向代理組態
Nextcloud 運行在 Docker 容器內部,使用 Apache 作為 Web 伺服器。為了整合到現有的 NGINX 基礎架構中,我們需要組態 NGINX 作為反向代理,將外部的 HTTPS 請求轉發到容器內部的 Apache 服務。
在 /etc/nginx/sites-available/ 目錄建立 Nextcloud 的虛擬主機組態檔案。
upstream nextcloud_backend {
server 127.0.0.1:11000;
keepalive 64;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name nextcloud.example.com;
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name nextcloud.example.com;
ssl_certificate /etc/letsencrypt/live/nextcloud.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nextcloud.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/nextcloud.example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
client_max_body_size 10G;
client_body_buffer_size 400M;
client_body_timeout 300s;
fastcgi_buffers 64 4K;
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/webfinger {
return 301 $scheme://$host/index.php/.well-known/webfinger;
}
location = /.well-known/nodeinfo {
return 301 $scheme://$host/index.php/.well-known/nodeinfo;
}
location / {
proxy_pass http://nextcloud_backend;
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;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_read_timeout 3600s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
}
}
這個反向代理組態包含了多個針對 Nextcloud 的特殊優化。Upstream 定義使用 keepalive 連線池,在 NGINX 與後端 Apache 之間保持持久連線,減少 TCP 握手的開銷,提升轉發效能。
安全標頭經過特別調整以符合 Nextcloud 的需求。Referrer-Policy 設定為 no-referrer 防止在外部連結中洩漏 Nextcloud 的內部路徑。X-Robots-Tag 指示搜尋引擎不要索引 Nextcloud 的內容,保護隱私。
客戶端請求大小限制設定為 10GB,與 Docker Compose 中的設定一致,確保使用者能夠上傳大型檔案。緩衝區設定為 400MB,對於大檔案上傳,NGINX 會將請求體先寫入磁碟暫存,避免記憶體耗盡。
WebDAV 相關的 .well-known 端點重導向是 Nextcloud 正確運作的必要組態。許多 CalDAV 與 CardDAV 客戶端會嘗試透過這些標準化的端點發現服務,正確的重導向確保這些客戶端能夠自動組態連線。
反向代理的標頭設定讓後端的 Nextcloud 能夠正確識別客戶端的真實 IP 位址與連線協定。X-Forwarded-For 標頭包含了客戶端的原始 IP 與所有中間代理的 IP,Nextcloud 使用這個資訊記錄存取日誌與執行安全檢查。X-Forwarded-Proto 告知後端客戶端使用的是 HTTPS 連線,即使代理與後端之間使用 HTTP,Nextcloud 仍能產生正確的 HTTPS URL。
WebSocket 支援透過 Upgrade 與 Connection 標頭實現,這對於 Nextcloud 的即時協作功能至關重要。當多個使用者同時編輯文件時,WebSocket 連線傳輸即時的編輯同步資訊,提供流暢的協作體驗。
proxy_buffering off 與 proxy_request_buffering off 停用了 NGINX 的請求與回應緩衝,這對於處理大檔案上傳下載非常重要。啟用緩衝時,NGINX 會先將整個請求或回應讀入記憶體或磁碟,然後才轉發,這會增加延遲並消耗大量資源。停用緩衝讓資料直接串流轉發,提供更好的效能與資源利用率。
超時設定配合 Nextcloud 的需求進行調整。proxy_read_timeout 設定為一小時,因為大檔案的上傳或下載可能需要較長時間。proxy_connect_timeout 與 proxy_send_timeout 設定為五分鐘,在網路不穩定時提供足夠的容錯空間。
完成組態後,啟用網站並驗證設定。
sudo ln -s /etc/nginx/sites-available/nextcloud.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
此時可以透過瀏覽器存取 https://nextcloud.example.com,完成 Nextcloud 的最終設定。首次存取時,Nextcloud 會要求建立管理員帳戶並進行基本組態。
在 Nextcloud 的管理介面中,檢查系統狀態與安全警告。Nextcloud 內建了安全檢查功能,會掃描常見的組態問題並提供修復建議。特別注意檢查資料庫組態、快取設定與背景任務組態,這些項目直接影響 Nextcloud 的效能與可靠性。
系統維運與故障排除實務
建立 WordPress 與 Nextcloud 的執行環境只是開始,持續的維運管理與問題處理能力決定了系統的長期穩定性。我們需要建立完善的監控機制、日誌分析流程與問題診斷方法,確保能夠快速發現並解決各類問題。
NGINX 日誌分析與監控
NGINX 的存取日誌與錯誤日誌是故障排除的主要資訊來源。存取日誌記錄了每個 HTTP 請求的詳細資訊,錯誤日誌則包含了伺服器運作過程中遇到的各種問題。
查看即時的存取日誌,監控當前的流量模式。
sudo tail -f /var/log/nginx/access.log
日誌的每一行記錄包含客戶端 IP、請求時間、HTTP 方法與路徑、狀態碼、回應大小、Referer 與 User-Agent 等資訊。透過分析這些資料,可以識別異常的存取模式,例如大量的 404 錯誤可能代表有人在掃描網站尋找漏洞,突然增加的流量可能是遭受攻擊或內容突然爆紅。
錯誤日誌包含更詳細的問題診斷資訊。
sudo tail -f /var/log/nginx/error.log
常見的錯誤訊息包括上游伺服器連線失敗、檔案不存在、權限拒絕等。錯誤日誌的等級從 debug、info、notice、warn、error 到 crit,可以根據需要調整日誌的詳細程度。在除錯組態問題時,可以暫時將日誌等級調整為 debug,取得更詳細的執行資訊。
分析特定時間段的存取模式,可以使用 awk 等文字處理工具。
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20
這個指令統計存取日誌中出現次數最多的前二十個 IP 位址,幫助識別可能的濫用或攻擊來源。
統計 HTTP 狀態碼的分佈。
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr
大量的 5xx 錯誤代表伺服器端問題,需要檢查應用程式與後端服務的狀態。大量的 4xx 錯誤可能是客戶端問題或掃描攻擊。
常見問題診斷與解決
當遇到 WordPress 或 Nextcloud 無法存取的情況時,系統化的故障排除流程能夠快速定位問題。
首先確認 NGINX 服務的運行狀態。
sudo systemctl status nginx
如果服務沒有運行,查看系統日誌找出原因。
sudo journalctl -u nginx -n 50
服務啟動失敗通常是組態檔案語法錯誤或埠口衝突。使用組態測試指令驗證。
sudo nginx -t
測試會明確指出錯誤的位置與性質,根據提示修正組態檔案。
如果 NGINX 正常運行但網站無法存取,檢查 PHP-FPM 服務的狀態。
sudo systemctl status php8.2-fpm
PHP-FPM 的錯誤日誌位於 /var/log/php8.2-fpm.log,包含 PHP 程式執行過程中的錯誤與警告。
對於 Nextcloud 的問題,檢查 Docker 容器的運行狀態。
sudo docker ps -a
sudo docker compose logs nextcloud-aio-mastercontainer
容器日誌會顯示 Nextcloud 應用程式層級的錯誤,包括資料庫連線問題、權限錯誤、組態異常等。
常見的 403 Forbidden 錯誤通常與檔案權限有關。確認 WordPress 目錄的擁有者與權限設定。
ls -la /var/www/wordpress
如果權限不正確,重新設定。
sudo chown -R wordpress:wordpress /var/www/wordpress
sudo find /var/www/wordpress -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress -type f -exec chmod 644 {} \;
502 Bad Gateway 錯誤代表 NGINX 無法連線到上游服務。對於 WordPress,檢查 PHP-FPM Socket 是否存在。
ls -la /var/run/php/php8.2-fpm.sock
如果 Socket 檔案不存在或權限不正確,重啟 PHP-FPM 服務。
sudo systemctl restart php8.2-fpm
對於 Nextcloud,檢查 Docker 容器是否正常運行且埠口綁定正確。
sudo docker port nextcloud-aio-mastercontainer
sudo netstat -tlnp | grep 11000
504 Gateway Timeout 錯誤代表上游服務回應時間過長。這可能是資料庫查詢緩慢、PHP 程式執行時間過長或資源不足。檢查系統資源使用情況。
top
df -h
free -m
如果記憶體或磁碟空間不足,需要優化應用程式組態或升級硬體資源。增加 NGINX 與 PHP-FPM 的超時設定可以暫時緩解問題,但根本解決還是需要優化應用程式效能。
效能優化與安全加固
持續的效能監控與優化確保系統能夠應對不斷增長的流量與資料。啟用 NGINX 的狀態監控模組,取得即時的效能指標。
server {
listen 127.0.0.1:8888;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
透過存取 http://localhost:8888/nginx_status 可以查看活動連線數、請求總數、讀寫狀態等資訊,這些指標幫助評估伺服器的負載狀況。
資料庫效能優化是 WordPress 效能提升的關鍵。啟用 MySQL 的慢查詢日誌,識別需要優化的查詢。
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log';
定期分析慢查詢日誌,針對頻繁出現的慢查詢建立索引或優化查詢邏輯。
WordPress 快取外掛如 WP Super Cache 或 W3 Total Cache 能夠顯著提升靜態內容的服務速度,減少資料庫查詢與 PHP 執行的負擔。配合 NGINX 的快取功能,可以實現多層次的快取策略。
安全性方面,定期更新所有軟體元件至最新版本,修補已知的安全漏洞。設定自動化的安全更新。
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
部署 Web 應用程式防火牆如 ModSecurity,過濾惡意請求與攻擊嘗試。配合 fail2ban 實施基於日誌的自動封鎖,當偵測到暴力破解或掃描行為時自動封鎖來源 IP。
定期的安全稽核與滲透測試幫助發現潛在的安全弱點。使用工具如 WPScan 掃描 WordPress 的已知漏洞,Lynis 進行系統層級的安全檢查。
最佳實踐建議
透過本文詳盡的技術解析與實務操作,我們成功建立了一個在 NGINX 伺服器上同時託管 WordPress 與 Nextcloud 的完整環境。這個整合式部署方案充分展現了現代 Web 基礎架構的靈活性與效率,透過混合使用傳統的直接安裝與容器化技術,我們獲得了兩種部署模式的優勢,同時避免了各自的劣勢。
WordPress 的直接安裝提供了最直接的檔案系統存取與最簡單的維護流程,適合需要頻繁客製化的內容管理需求。完整的 NGINX 與 PHP-FPM 組態優化,搭配 MySQL 資料庫的適當調校,確保了網站能夠提供快速且穩定的使用者體驗。SSL/TLS 的完整組態與安全標頭的適當設定,保護了使用者與伺服器之間的通訊安全,符合現代 Web 安全的標準要求。
Nextcloud 的容器化部署展示了 Docker 技術在簡化複雜應用程式部署方面的強大能力。透過 All-in-One 映像與 Docker Compose 編排,我們在幾分鐘內就建立了包含多個相依服務的完整 Nextcloud 環境,避免了手動安裝與組態每個元件的繁瑣過程。NGINX 反向代理的整合讓容器化的應用程式能夠無縫融入現有的 Web 基礎架構,提供統一的 SSL 終端與流量管理。
在維運層面,完善的日誌機制與系統化的故障排除流程是確保長期穩定運作的關鍵。透過持續監控伺服器效能指標、定期分析日誌資料、快速響應安全警報,我們能夠在問題影響使用者之前就發現並解決。自動化的備份策略與災難恢復計畫則提供了最後的安全網,確保即使在最糟糕的情況下也能快速恢復服務。
未來的優化方向包括引入內容分發網路加速靜態資源的全球分發,部署負載平衡器實現水平擴展,整合進階的監控與告警系統提供更全面的可觀測性。隨著流量與資料的增長,可以考慮將資料庫遷移到專用的伺服器,或採用讀寫分離架構提升資料庫效能。容器編排平台如 Kubernetes 能夠提供更強大的自動化管理能力,但也帶來了額外的複雜度,需要根據實際需求評估是否值得投資。
對於規劃部署類似環境的讀者,建議從小規模開始,逐步驗證每個元件的組態與整合,確保完全理解系統的運作原理後再擴展到生產環境。充分的測試與文件記錄是成功部署的基礎,清楚記載每個組態選項的用途與變更歷史,能夠大幅降低未來維護與問題診斷的難度。持續學習與追蹤技術發展,及時更新系統元件與組態最佳實踐,是維持系統安全性與效能的必要投資。