Web 服务器是网站的引擎。本指南帮您在 Nginx、Apache、Caddy 中做出正确选择,并手把手完成安装、PHP-FPM 集成、反向代理,以及用 Certbot 或 acme.sh 申请 SSL 证书——从零到一个完整的 HTTPS 站点。
⚖️ 选型对比:Nginx / Apache / Caddy
在开始安装前,先了解三位"选手"的核心差异,选对工具能让您事半功倍。
Nginx
高性能反向代理首选- +异步事件驱动,万级并发轻松应对
- +内存占用极低(约 2-3MB/worker)
- +反向代理与负载均衡功能强大
- +静态文件服务性能业界最优
- –配置语法需要一定学习成本
- –动态配置需要 reload(无 .htaccess)
静态网站、反向代理、API 网关、高并发场景
Apache
老牌生态最完整- +.htaccess 支持目录级动态配置
- +PHP mod_php 深度集成,零配置
- +模块生态最丰富,文档最完善
- +兼容大量老旧 PHP 应用
- –高并发下每连接一线程,内存消耗大
- –默认配置性能不如 Nginx
传统 PHP 应用(WordPress/Drupal)、需要 .htaccess 的场景
Caddy
零配置自动 HTTPS- +自动申请、配置、续期 SSL 证书
- +配置文件极简,3行搞定 HTTPS 站点
- +原生支持 HTTP/2 和 HTTP/3
- +Go 语言编写,单二进制无依赖
- –生态和社区不如 Nginx/Apache 成熟
- –高级调优选项较少
个人项目、快速原型、不想折腾 SSL 的场景
💡 一句话推荐:不知道选哪个?选 Nginx——它覆盖了 95% 的场景。只有两种例外:① 您的 PHP 应用依赖 .htaccess 动态配置 → 选 Apache;② 您不想碰 SSL 配置,要最省心 → 选 Caddy。
🟢 Nginx:安装、配置与性能调优
Nginx(发音 "engine-x")以异步事件驱动架构著称,单进程可处理数万并发连接,是目前最主流的 Web 服务器,全球市占率超过 35%。
安装与验证
# ── Ubuntu / Debian ──────────────────────────────────────────────────────────
sudo apt update && sudo apt install nginx -y
# 启动并设置开机自启
sudo systemctl enable --now nginx
# 验证安装:访问 http://服务器IP 应看到 "Welcome to nginx!" 页面
curl -I http://localhost # 应返回 200 OK
# ── CentOS / AlmaLinux / RHEL ─────────────────────────────────────────────────
sudo yum install nginx -y
sudo systemctl enable --now nginx 📁 Nginx 核心目录速查
/etc/nginx/nginx.conf 主配置文件:全局 worker、日志、http 块 /etc/nginx/conf.d/*.conf 站点配置目录(CentOS 直接生效) /etc/nginx/sites-available/ 站点配置存放目录(Ubuntu/Debian) /etc/nginx/sites-enabled/ 已激活的站点(软链接到 sites-available) /var/log/nginx/access.log 访问日志(每条请求) /var/log/nginx/error.log 错误日志(排查问题首选) 静态网站配置
# 文件路径:/etc/nginx/conf.d/mysite.conf
# Ubuntu/Debian 也可放到 /etc/nginx/sites-available/mysite.conf(需创建软链接激活)
server {
listen 80;
listen [::]:80; # 同时监听 IPv6
server_name example.com www.example.com; # 您的域名
root /var/www/mysite; # 网站根目录
index index.html index.htm index.php; # 默认首页文件顺序
# 日志(每个站点独立日志,便于排查)
access_log /var/log/nginx/mysite_access.log;
error_log /var/log/nginx/mysite_error.log warn;
# 静态文件请求处理:先找文件,再找目录,最后返回 404
location / {
try_files $uri $uri/ =404;
}
# 静态资源长期缓存(图片/CSS/JS/字体)
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 禁止访问隐藏文件(.git/.env 等)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
} 性能调优:nginx.conf 全局优化
# 文件路径:/etc/nginx/nginx.conf
# 以下配置针对 2核4GB 服务器调优,根据实际硬件调整数值
# ── 全局块 ────────────────────────────────────────────────────────────────────
worker_processes auto; # 自动匹配 CPU 核心数(推荐)
worker_rlimit_nofile 65535; # 每个 worker 进程最大打开文件数
events {
worker_connections 4096; # 每个 worker 的最大并发连接数
multi_accept on; # 一次接受所有新连接(提升突发连接效率)
use epoll; # Linux 最高效的 I/O 事件模型
}
http {
# ── 基础安全 ──────────────────────────────────────────────────────────────
server_tokens off; # 隐藏 Nginx 版本号(防止版本探测)
# ── 连接优化 ──────────────────────────────────────────────────────────────
keepalive_timeout 65; # 保持 HTTP 长连接 65 秒
keepalive_requests 1000; # 单个长连接最多处理 1000 个请求
client_header_timeout 15; # 读取请求头超时(防慢速攻击)
client_body_timeout 15;
send_timeout 15;
# ── Gzip 压缩(减少 60-80% 传输体积)────────────────────────────────────
gzip on;
gzip_vary on; # 告知代理服务器缓存 gzip 版本
gzip_proxied any; # 对代理请求也压缩
gzip_comp_level 6; # 压缩级别 1-9,6 是性能与压缩率的最佳平衡点
gzip_min_length 1000; # 小于 1KB 的响应不压缩
gzip_types
text/plain text/css text/xml text/javascript
application/json application/javascript application/xml
application/x-font-ttf font/opentype image/svg+xml;
# ── 文件缓存(减少磁盘 I/O)───────────────────────────────────────────────
open_file_cache max=10000 inactive=30s; # 缓存最多 10000 个文件描述符
open_file_cache_valid 60s;
open_file_cache_min_uses 2; # 至少访问 2 次才缓存
open_file_cache_errors on;
# ── 请求限速(防 CC 攻击,从第12篇 security-advanced 引入)────────────────
limit_req_zone $binary_remote_addr zone=perip:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
include /etc/nginx/conf.d/*.conf;
} 反向代理配置
# 反向代理:将域名请求转发到后端应用(Node.js/Python/Go 等)
# 文件路径:/etc/nginx/conf.d/api.conf
upstream backend_app {
# keepalive 保持与后端的持久连接,减少 TCP 握手开销
keepalive 32;
server 127.0.0.1:3000; # 后端应用地址和端口
# server 127.0.0.1:3001; # 可以添加多个后端实现负载均衡
}
server {
listen 80;
server_name api.example.com;
# 应用连接限速规则
limit_req zone=perip burst=50 nodelay;
location / {
proxy_pass http://backend_app;
proxy_http_version 1.1;
# WebSocket 支持(如果后端有 WS 连接需要这两行)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 传递真实客户端信息到后端
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;
# 超时配置(后端响应超过此时间返回 504)
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲区(防止后端慢速导致 worker 阻塞)
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 16 8k;
}
} 负载均衡配置
# 负载均衡:将流量分散到多台后端服务器
upstream web_cluster {
# least_conn:将请求发到当前连接数最少的服务器(适合耗时不均的请求)
least_conn;
server backend1.example.com:8080 weight=3; # weight 越大获得越多流量
server backend2.example.com:8080 weight=2;
server backend3.example.com:8080 weight=1;
# backup:仅在其他服务器全部不可用时启用
# server backup.example.com:8080 backup;
keepalive 64;
}
# 其他负载均衡策略:
# round_robin(默认):轮询,最简单
# ip_hash:同一 IP 始终路由到同一后端(适合 Session 不共享的场景)
# hash $request_uri consistent:按 URL 哈希(适合缓存命中率优化) 🐘 实战:Nginx + PHP-FPM 完整部署
PHP-FPM(FastCGI Process Manager)是 Nginx 处理 PHP 的标准方案。与 Apache 的 mod_php 不同,PHP-FPM 作为独立进程运行,Nginx 通过 Unix Socket 与其通信,资源占用更低,性能更好。
安装 PHP 8.3 + PHP-FPM
# ── 安装 PHP 8.3 和 PHP-FPM ────────────────────────────────────────────────
# Ubuntu 22.04+ / Debian 12 使用 ondrej/php PPA 获取最新版
apt install -y software-properties-common
add-apt-repository ppa:ondrej/php -y # Ubuntu 专用,Debian 跳过此步
apt update
# 安装 PHP-FPM 和 WordPress 常用扩展
apt install -y php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-intl php8.3-mbstring php8.3-xml php8.3-zip php8.3-bcmath php8.3-imagick
# 启动 PHP-FPM
systemctl enable --now php8.3-fpm
# 验证 PHP-FPM 正在运行(监听 Unix socket)
ls -la /run/php/php8.3-fpm.sock # 应存在此 socket 文件 Nginx 配置 PHP-FPM(WordPress 完整示例)
# 文件路径:/etc/nginx/conf.d/wordpress.conf
# WordPress + Nginx + PHP-FPM 完整配置
server {
listen 80;
server_name yourblog.com www.yourblog.com;
root /var/www/wordpress;
index index.php index.html;
# WordPress 固定链接支持
location / {
try_files $uri $uri/ /index.php?$args;
}
# PHP 文件通过 FastCGI 交给 PHP-FPM 处理
location ~ \.php$ {
# 防止 Nginx 处理不存在的 PHP 文件(安全)
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# 连接 PHP-FPM(Unix socket 比 TCP 快约 10%)
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
# 传递标准 FastCGI 参数
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
# FastCGI 缓冲(减少 PHP-FPM 进程等待时间)
fastcgi_buffering on;
fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;
fastcgi_read_timeout 120s;
}
# WordPress 上传文件大小限制
client_max_body_size 64M;
# 禁止访问 WordPress 敏感文件
location ~* /wp-config\.php { deny all; }
location ~* /xmlrpc\.php { deny all; } # 禁用 XML-RPC 防暴力破解
location ~* /\. { deny all; } # 禁止访问隐藏文件
} PHP-FPM 进程池调优
# 文件路径:/etc/php/8.3/fpm/pool.d/www.conf
# PHP-FPM 进程池配置(根据服务器内存调整)
[www]
user = www-data
group = www-data
# ── 进程管理模式 ──────────────────────────────────────────────────────────────
# dynamic(推荐):根据负载动态调整进程数,平衡性能与内存
pm = dynamic
# 进程数参考公式(以每个 PHP 进程占 50MB 内存为例):
# pm.max_children = 可用内存(MB) / 50
pm.max_children = 20 # 1GB 内存约设 20
pm.start_servers = 5 # 启动时初始化 5 个进程
pm.min_spare_servers = 3 # 最少保留 3 个空闲进程
pm.max_spare_servers = 8 # 最多保留 8 个空闲进程
# 每个进程处理 500 个请求后重启(防内存泄漏)
pm.max_requests = 500
# ── PHP 运行时配置(覆盖 php.ini)────────────────────────────────────────────
php_value[memory_limit] = 256M
php_value[upload_max_filesize] = 64M
php_value[post_max_size] = 64M
php_value[max_execution_time] = 120
# 开启 PHP-FPM 慢日志(记录超过 5 秒的请求,性能调优利器)
slowlog = /var/log/php8.3-fpm-slow.log
request_slowlog_timeout = 5s 🔴 Apache:安装、虚拟主机与 PHP 集成
Apache 拥有 30 年历史,其 mod_php 深度集成让 PHP 应用的部署极其简单,.htaccess 的目录级动态配置也让它在共享主机环境中无可替代。
安装 Apache
# ── Ubuntu / Debian ──────────────────────────────────────────────────────────
sudo apt update && sudo apt install apache2 -y
sudo systemctl enable --now apache2
# ── CentOS / RHEL(软件包名为 httpd)─────────────────────────────────────────
sudo yum install httpd -y
sudo systemctl enable --now httpd
# 验证:访问 http://服务器IP 应看到 Apache 欢迎页
curl -I http://localhost 虚拟主机配置
# 文件路径:/etc/apache2/sites-available/mysite.conf(Ubuntu)
# CentOS:/etc/httpd/conf.d/mysite.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/mysite
<Directory /var/www/mysite>
Options -Indexes +FollowSymLinks # 禁止目录浏览,允许符号链接
AllowOverride All # 允许 .htaccess(如不需要改 None 提升性能)
Require all granted
</Directory>
# 日志(每站点独立)
ErrorLog ${APACHE_LOG_DIR}/mysite_error.log
CustomLog ${APACHE_LOG_DIR}/mysite_access.log combined
</VirtualHost>
# ── Ubuntu 激活站点 ───────────────────────────────────────────────────────────
# sudo a2ensite mysite.conf
# sudo a2enmod rewrite # 启用 URL 重写模块(WordPress 必需)
# sudo systemctl reload apache2 .htaccess 配置(URL 重写与安全规则)
# 文件路径:/var/www/mysite/.htaccess
# 注意:AllowOverride All 时 Apache 才会读取此文件
# ── 开启 URL 重写 ─────────────────────────────────────────────────────────────
RewriteEngine On
# 强制 HTTPS(HTTP 全部跳转到 HTTPS)
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# 去除 www 前缀(统一规范 URL)
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# WordPress 固定链接(所有 PHP 不存在的路径交给 index.php)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]
# 禁止访问敏感文件
<FilesMatch "^(\.env|\.git|wp-config\.php|readme\.html)">
Require all denied
</FilesMatch> 常用模块管理与 PHP 集成
sudo a2enmod rewrite URL 重写(WordPress/Laravel 必需)
sudo a2enmod ssl SSL/HTTPS 支持
sudo a2enmod headers 自定义 HTTP 响应头
sudo a2enmod deflate Gzip 压缩
sudo a2enmod expires 浏览器缓存控制
sudo a2ensite mysite 激活站点配置
模块变更后执行 sudo systemctl restart apache2 生效。PHP 集成:sudo apt install php libapache2-mod-php php-mysql -y,安装后 Apache 自动加载 PHP 模块,无需额外配置。
🔵 Caddy:零配置自动 HTTPS
Caddy 是最省心的 Web 服务器——它会自动申请 Let's Encrypt 证书、自动续期、自动将 HTTP 跳转到 HTTPS,您只需写几行配置文件。
安装 Caddy
# ── Ubuntu / Debian ──────────────────────────────────────────────────────────
# 添加 Caddy 官方 APT 源
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install caddy -y
# ── CentOS / RHEL ─────────────────────────────────────────────────────────────
# 参考官方文档:https://caddyserver.com/docs/install#fedora-redhat-centos
# 验证安装
systemctl status caddy
caddy version 最简 Caddyfile(3行搞定 HTTPS 站点)
# 文件路径:/etc/caddy/Caddyfile
# 这 3 行就是一个完整的 HTTPS 静态网站!
example.com {
root * /var/www/mysite # 网站根目录
file_server # 开启文件服务器(自动处理静态文件)
# Caddy 自动为 example.com 申请 Let's Encrypt 证书,自动续期,自动 HTTP→HTTPS 跳转
} ✨ Caddy 的自动化魔法: 只要域名已解析到本服务器,Caddy 就会自动完成:① 向 Let's Encrypt 申请证书 → ② 配置 HTTPS → ③ 设置 HTTP 自动跳转 → ④ 90 天后自动续期。前提:80 和 443 端口对外开放,且服务器能访问公网。
高级 Caddyfile(多域名、反代、PHP-FPM)
# 文件路径:/etc/caddy/Caddyfile
# 完整的高级配置示例
# 主站:静态 + PHP 博客
example.com {
root * /var/www/mysite
file_server
encode gzip # 启用 Gzip 压缩
# 反向代理特定路径到后端 API
reverse_proxy /api/* localhost:3000
# PHP-FPM 集成
php_fastcgi unix//run/php/php8.3-fpm.sock
# 安全响应头
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
-Server # 删除 Server 响应头
}
# 自定义日志格式
log {
output file /var/log/caddy/example.log {
roll_size 100mb
roll_keep 10
}
format console
}
}
# API 子域名:纯反向代理
api.example.com {
reverse_proxy localhost:8080
}
# 图床子域名:静态文件服务
cdn.example.com {
root * /var/www/uploads
file_server browse # browse 显示目录列表(内部使用)
}
# 重载配置(不中断现有连接)
# sudo systemctl reload caddy 🔒 SSL 证书:Certbot 与 acme.sh 双方案
HTTPS 已是现代网站的标配,对 SEO 和用户信任都有直接影响。以下提供两套证书申请方案:Certbot(官方工具,自动修改 Nginx/Apache 配置)和 acme.sh(纯 Shell 脚本,支持泛域名和 DNS 验证,无需开放 80 端口)。
🤖Certbot
- 官方 EFF 维护,文档最全
- 自动修改 Nginx/Apache 配置
- 新手最友好
适合:首次配置 SSL,单一域名场景
⚡acme.sh
- 支持 *.example.com 泛域名
- DNS 验证无需开放 80 端口
- 支持多个 CA(Let's Encrypt/ZeroSSL)
适合:泛域名证书、CDN 场景、无 80 端口
方案一:Certbot(推荐新手)
# ── Ubuntu / Debian ──────────────────────────────────────────────────────────
sudo apt install certbot python3-certbot-nginx python3-certbot-apache -y
# ── CentOS / RHEL(需要 EPEL)─────────────────────────────────────────────────
sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-nginx python3-certbot-apache -y # ── 方式一:自动模式(推荐,Certbot 自动修改 Nginx/Apache 配置)─────────────
# Nginx:
sudo certbot --nginx -d example.com -d www.example.com
# 按提示:输入邮箱 → 同意条款 → 选择是否跳转 HTTPS → 完成
# Apache:
sudo certbot --apache -d example.com -d www.example.com
# ── 方式二:certonly 模式(只获取证书,手动配置)──────────────────────────────
# 适合:使用 Docker 或非标准路径的场景
sudo certbot certonly --webroot -w /var/www/mysite -d example.com -d www.example.com --email admin@example.com --agree-tos
# 证书文件位置:
# 证书:/etc/letsencrypt/live/example.com/fullchain.pem
# 私钥:/etc/letsencrypt/live/example.com/privkey.pem
# ── 验证自动续期 ──────────────────────────────────────────────────────────────
sudo certbot renew --dry-run # 模拟续期(不实际执行)
sudo certbot certificates # 查看所有证书及到期时间 方案二:acme.sh 申请泛域名证书(进阶推荐)
# ── acme.sh 申请泛域名证书(优于 Certbot 的场景:泛域名、DNS 验证、多 CA)──
# 优势:纯 Shell 脚本无依赖、支持 *.example.com 泛域名、支持 ZeroSSL/Let's Encrypt
# 1. 安装 acme.sh
curl https://get.acme.sh | sh -s email=admin@example.com
source ~/.bashrc # 或重新打开终端
# 2. 配置 Cloudflare DNS API(用于 DNS-01 验证,无需 80 端口开放)
# 在 CF 后台 → 我的个人资料 → API 令牌 → 创建令牌(Zone DNS 编辑权限)
export CF_Token="your_cloudflare_api_token"
export CF_Zone_ID="your_zone_id"
# 3. 申请泛域名证书(* 号匹配所有子域名)
acme.sh --issue --dns dns_cf -d example.com -d "*.example.com" --server letsencrypt # 可选 --server zerossl 使用 ZeroSSL
# 4. 安装证书到 Nginx 目录
acme.sh --install-cert -d example.com -d "*.example.com" --cert-file /etc/nginx/ssl/example.com/cert.pem --key-file /etc/nginx/ssl/example.com/key.pem --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem --reloadcmd "systemctl reload nginx" # 安装后自动 reload
# 5. acme.sh 自动添加 Cron 任务,每天检查并在到期前 30 天自动续期
# 查看:crontab -l | grep acme Nginx HTTPS 完整配置(含 HTTP/2 和安全响应头)
# 申请证书后,将 HTTP server 块升级为 HTTPS
# 文件路径:/etc/nginx/conf.d/mysite.conf
# HTTP → HTTPS 跳转
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPS 主配置
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on; # 启用 HTTP/2(提升多资源加载速度)
server_name example.com www.example.com;
# 证书路径(Certbot 自动填充 / acme.sh 手动指定)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ── SSL 安全配置(Mozilla 现代级别)──────────────────────────────────────
ssl_protocols TLSv1.2 TLSv1.3; # 只允许 TLS 1.2/1.3,禁用旧版
ssl_prefer_server_ciphers off; # 让客户端选择最佳密码套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
# SSL Session 复用(减少重复握手开销)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# HSTS:强制浏览器永远使用 HTTPS(慎用,设置后很难撤销)
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;
server_tokens off;
root /var/www/mysite;
index index.html;
location / {
try_files $uri $uri/ =404;
}
} 🔧 故障排查速查手册
# ════════════════════════════════════════════════════════════════════
# Web 服务器故障排查速查手册
# ════════════════════════════════════════════════════════════════════
# ── 通用:查看服务状态与日志 ──────────────────────────────────────────────────
systemctl status nginx # 服务是否运行
journalctl -u nginx -n 50 -p err # 最近 50 条 error 日志
tail -f /var/log/nginx/error.log # 实时错误日志
# ── Nginx:配置语法检查与重载 ─────────────────────────────────────────────────
nginx -t # 测试配置文件语法(出错显示具体位置)
systemctl reload nginx # 语法无误后优雅重载(不中断连接)
# !永远不要跳过 nginx -t 直接 reload,语法错误会导致 Nginx 完全停止
# ── 端口占用检查 ──────────────────────────────────────────────────────────────
ss -tlnp | grep ':80|:443' # 查看 80/443 端口被哪个进程占用
lsof -i :80 # 同上,另一种方式
# ── 权限问题(403 Forbidden)─────────────────────────────────────────────────
# Nginx 以 www-data 用户运行,网站目录必须对其可读
chown -R www-data:www-data /var/www/mysite
chmod -R 755 /var/www/mysite # 目录 755,文件 644
chmod 644 /var/www/mysite/index.html
# ── PHP-FPM 连接问题 ──────────────────────────────────────────────────────────
systemctl status php8.3-fpm # FPM 是否运行
ls -la /run/php/php8.3-fpm.sock # socket 文件是否存在
# 若 socket 不存在,检查 /etc/php/8.3/fpm/pool.d/www.conf 中的 listen 配置
# ── SSL 证书问题 ──────────────────────────────────────────────────────────────
openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# 输出 notAfter 即到期时间
certbot certificates # 查看所有证书状态 启动 Nginx 报错"端口已被占用"(Address already in use)
80/443 端口被其他进程占用。排查步骤:① ss -tlnp | grep ':80' 查看占用进程;② 常见"凶手":Apache(systemctl stop apache2)、面板安装的 Nginx(systemctl stop openresty)、Python 测试服务器;③ 若需要两个服务共存,给其中一个改端口,前面用 Nginx 做反向代理统一出口。
访问网站显示 403 Forbidden
三种常见原因:① 权限问题:chown -R www-data:www-data /var/www/mysite && chmod -R 755 /var/www/mysite;② 缺少索引文件:目录下没有 index.html/index.php,且配置了 try_files ... =404;③ SELinux 拦截(CentOS):chcon -Rt httpd_sys_content_t /var/www/mysite 或临时 setenforce 0 测试是否是 SELinux 原因。
502 Bad Gateway(反向代理场景)
Nginx 无法连接后端服务。检查顺序:① curl http://localhost:3000 直接测试后端是否响应;② systemctl status 后端服务名 确认服务在运行;③ 检查 proxy_pass 中的端口与后端实际监听端口是否一致;④ 查看 tail -f /var/log/nginx/error.log 获取具体错误原因——"connection refused" 表示后端没运行,"timeout" 表示后端运行但响应太慢。
Certbot 申请证书失败
按可能性从高到低排查:① DNS 未生效:dig example.com 确认解析到当前服务器 IP;② 80 端口被防火墙拦截:ufw allow 80/tcp,Let's Encrypt 的 HTTP-01 验证必须能访问 80 端口;③ Nginx/Apache 未运行:Certbot 需要 Web 服务器配合完成验证;④ 频率限制:同一域名每周最多申请 5 次,超限需等 7 天,可用 --staging 参数测试(不消耗配额);⑤ 备选:改用 acme.sh + DNS API 验证,完全绕开 80 端口问题。
PHP 文件直接下载而不执行(显示代码而不是网页)
Nginx 没有配置 PHP-FPM 处理 .php 文件。确认 Nginx 配置中有正确的 location ~ \.php$ 块,并且 fastcgi_pass 指向的 socket 路径与 PHP-FPM 实际 socket 路径一致(ls /run/php/ 查看实际路径)。Apache 则确认已安装 libapache2-mod-php 并执行 a2enmod php8.3。
修改配置后不生效
修改配置后必须重载服务:Nginx → nginx -t && systemctl reload nginx(先测试语法);Apache → apachectl configtest && systemctl reload apache2;Caddy → systemctl reload caddy。浏览器缓存也是常见"元凶"——用 Chrome 按 Ctrl+Shift+R 强制刷新,或开无痕窗口测试。Ubuntu 的 sites-available 配置还需要 a2ensite/ln -s 创建软链接激活,否则修改不会被读取。
如何查看 Web 服务器实时日志?
Nginx 错误日志:tail -f /var/log/nginx/error.log;访问日志:tail -f /var/log/nginx/access.log。Apache:tail -f /var/log/apache2/error.log。Caddy:journalctl -u caddy -f。用 grep " 500 \| 502 \| 503 " /var/log/nginx/access.log | tail -20 快速过滤错误请求。详细的日志分析方法参见第 12 篇日志分析指南。
Nginx 性能测试显示并发很低,如何优化?
按影响程度从大到小排查:① worker_processes:确认设为 auto(匹配 CPU 核心数);② worker_connections:从默认 1024 提升到 4096;③ 系统文件描述符限制:ulimit -n 默认可能只有 1024,执行 ulimit -n 65535 提升,同时在 nginx.conf 加 worker_rlimit_nofile 65535;④ keepalive_timeout:适当延长(65-120s)减少 TCP 握手次数;⑤ 瓶颈在后端:若是反向代理场景,通常瓶颈在 PHP-FPM/数据库而非 Nginx 本身,用 ab -n 1000 -c 100 http://localhost/ 先测静态文件响应速度定位瓶颈。
❓ 常见问题解答
Nginx 和 Apache 可以同时安装在一台服务器上吗?
可以安装,但不能同时监听 80/443 端口。经典方案:让 Nginx 监听 80/443 对外,Apache 监听 8080/8888 对内,Nginx 将动态 PHP 请求反代到 Apache(proxy_pass http://127.0.0.1:8080)。但这种架构增加了复杂度,现代方案推荐 Nginx + PHP-FPM 的组合,比 Nginx + Apache 性能更好,资源占用更低。只有当您有无法去掉 .htaccess 的老 PHP 应用时,才值得考虑双服务器方案。
Let's Encrypt 的免费证书和付费证书有什么区别?值得买付费证书吗?
对于绝大多数个人站长和中小企业,Let's Encrypt 免费证书完全够用——它提供的加密强度与付费证书完全相同,浏览器显示的"🔒"小锁也没有区别。付费证书主要差异:① OV(组织验证)证书:CA 会验证公司真实性,证书信息中显示公司名称,适合有公信力要求的企业;② EV(扩展验证)证书:最高级别验证,以前浏览器会显示绿色地址栏(现代浏览器已取消),金融/政府机构使用;③ 通配符付费证书:一次购买可用于所有子域名,而 Let's Encrypt 的泛域名证书通过 acme.sh 可以免费获得。结论:个人博客/企业官网/API 服务用 Let's Encrypt 完全足够;只有银行/证券/政府类网站才需要考虑 OV/EV 付费证书。
服务器已经用了 1Panel 面板管理 Nginx,还需要学手动配置吗?
强烈建议学。原因:① 面板出问题时需要手动排查:当面板显示 "Nginx 配置错误" 时,您需要能读懂 /etc/nginx/conf.d/ 下的具体配置文件来定位问题;② 面板的"自定义配置"框需要你写 Nginx 语法:实现复杂的 location 规则、特殊 Header 配置时,面板只提供了输入框,内容要您自己写;③ 理解底层让您更有掌控感:知道面板的"反向代理"按钮背后生成了什么配置,出了问题才能从容应对。第 13 篇的面板是加速器,本篇是理解地基——两者互为补充,不是替代关系。
HTTP/2 和 HTTP/3 有什么区别?应该开哪个?
HTTP/1.1(默认):每个资源串行请求,浏览器开多个 TCP 连接来并行加载。HTTP/2:单个 TCP 连接上多路复用,一次请求可同时传输多个资源,对多资源页面(CSS/JS/图片多的网站)提升明显(20-30%)。HTTP/3:基于 UDP 的 QUIC 协议,解决了 TCP 的队头阻塞问题,对高延迟/丢包网络(移动网络)有更大提升。推荐配置:在 Nginx 的 listen 443 行加 http2 on; 开启 HTTP/2,这是目前生产环境的最佳实践,几乎零风险。HTTP/3 需要 Nginx 1.25.0+ 且系统支持 QUIC,目前仍属于进阶配置,个人站点可以尝试,企业生产环境谨慎开启。
WordPress 部署在 Nginx 上,固定链接 404,是什么原因?
WordPress 的固定链接(如 /2026/03/my-post/)依赖 URL 重写,Nginx 需要正确配置 try_files。在 Nginx 的 server 块 location / 中添加:try_files $uri $uri/ /index.php?$args;——这行的含义是:先找文件,再找目录,都不存在就交给 index.php 处理(WordPress 的路由入口)。缺少这行就会导致固定链接 404。如果是 Apache,则需要确认已启用 mod_rewrite 并且 AllowOverride All,WordPress 会通过 .htaccess 自动添加重写规则。
一台 Nginx 服务器能托管多少个网站?有数量限制吗?
Nginx 本身没有站点数量上限,每个站点对应 conf.d/ 下的一个 .conf 文件,Nginx 启动时全部加载到内存。实际限制来自服务器资源:① 内存是主要瓶颈——每个站点的 PHP-FPM 进程池、MySQL 连接占用内存,一台 2GB 的服务器托管 5-10 个中低流量 PHP 站点完全没问题;② 磁盘 I/O:大量站点同时有访问时,磁盘读写可能成为瓶颈;③ 数据库连接数:MySQL 默认最大连接数 151,多站点共用时可能不够。经验值:2GB 内存的 VPS 稳定托管 5-8 个 WordPress,4GB 可以托管 15-20 个低流量站点。
Caddy 的自动证书存储在哪里?能导出给 Nginx 用吗?
Caddy 将证书存储在 /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/(或 ~/.local/share/caddy/,取决于运行用户)。证书文件是标准的 PEM 格式,技术上可以复制给 Nginx 用,但不推荐这种做法——Caddy 自动续期后文件路径不变,但 Nginx 不会自动 reload,导致 Nginx 仍用旧证书。更好的做法:如果您需要 Nginx,直接用 Certbot 或 acme.sh 为 Nginx 申请证书;或者让 Caddy 作为前端代理,Nginx 在后端只处理逻辑,不直接面向公网。
学完 Web 服务器后,下一步应该怎么进阶?
按本站 30 篇路径,第 14 篇(本篇)→ 第 15 篇(docker-deployment)→ 第 16 篇(database-setup)是最紧密的进阶链条。关联逻辑:Docker 和 Nginx 是目前最流行的部署组合——Docker 管理应用容器,Nginx 作为前端反向代理统一对外服务;掌握了本篇的反向代理配置,在第 15 篇中把 proxy_pass 指向 Docker 容器就能实现完整的容器化部署。第 16 篇的数据库搭建则为您的 Web 应用提供数据存储能力,Nginx + PHP-FPM + MySQL 三件套构成了传统 LEMP 栈的全部组件。
PHP-FPM 的 pm.max_children 设置太小会有什么表现?如何判断需要调大?
当并发请求超过 pm.max_children 时,多余的请求会排队等待,表现为:① 网站响应时间突然变慢(从 0.1s 变成 3-5s);② Nginx 的 access.log 中出现大量 499(客户端等待超时后主动断开)或 502;③ /var/log/php8.3-fpm.log 中出现 WARNING: [pool www] server reached pm.max_children, consider raising it 这行警告——这是最直接的信号。调整公式:max_children = 可用物理内存 MB / 单个 PHP 进程内存 MB。查看单进程内存:ps --no-headers -o "rss,cmd" -C php-fpm8.3 | awk '{sum+=$1} END {print sum/NR/1024 "MB per process"}'。WordPress 通常每进程 50-80MB,1GB 内存(留 400MB 给系统和 MySQL)可设 max_children 约 15-20。