Nginx-星耀云
发布时间:2026-04-27 13:09
一、前言
搞过的人都知道,最烦的是Nginx配完了访问502、用着用着进程挂了、日志里一堆诡异错误根本不知道从哪查。新手上来就是server块复制粘贴,资深点的配置了一大堆但线上跑着跑着就出幺蛾子。本文不废话,直接给你一套能上生产环境的Nginx实战配置模板,从基础安装到高可用调优,手把手跑通。
二、操作步骤
第1步:确认系统环境并安装Nginx
CentOS/RHEL 执行:
sudo yum install -y epel-release
sudo yum install -y nginx
nginx -v
预期输出(CentOS/RHEL):
nginx version: nginx/1.20.1
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
Ubuntu 执行:
sudo apt-get update
sudo apt-get install -y nginx
nginx -v
预期输出(Ubuntu):
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f 31 Mar 2020
第2步:查看默认配置结构
CentOS/RHEL 执行:
ls -la /etc/nginx/
cat /etc/nginx/nginx.conf
预期输出(CentOS/RHEL):
total drwxr-xr-x 2 root root 4096 Dec 1 10:00 nginx.conf
drwxr-xr-x 3.15 root 6 Nov 9 2020 nginx.conf.default
conf.d/
default.d/
mime.types
mime.types.default
modules-enabled/
modules-available/
nginx.conf
nginx.conf.default
scgi_params
scgi_params.default
uwsgi_params
uwsgi_params.default
win-utf
Ubuntu 执行:
ls -la /etc/nginx/
cat /etc/nginx/nginx.conf
预期输出(Ubuntu):
conf.d/
fastcgi.conf
fastcgi.conf.default
fastcgi_params
fastcgi_params.default
koi-utf
koi-win
mime.types
mime.types.default
nginx.conf
nginx.conf.default
scgi_params
scgi_params.default
sites-available/
sites-enabled/
uwsgi_params
uwsgi_params.default
win-utf
第3步:创建站点配置文件
执行命令:
sudo mkdir -p /var/www/example.com/html
sudo chown -R www-data:www-data /var/www/example.com
echo '<html><body><h1>Nginx实战配置成功</h1></body></html>' | sudo tee /var/www/example.com/html/index.html
预期输出:
<html><body><h1>Nginx实战配置成功</h1></body></html>
创建站点配置文件:
sudo tee /etc/nginx/sites-available/example.com.conf <<'EOF'
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
access_log /var/log/nginx/example.com_access.log;
error_log /var/log/nginx/example.com_error.log;
location / {
try_files $uri $uri/ =404;
}
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
EOF
预期输出:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
access_log /var/log/nginx/example.com_access.log;
error_log /var/log/nginx/example.com_error.log;
location / {
try_files $uri $uri/ =404;
}
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
EOF
启用站点(创建软链接):
CentOS/RHEL 执行:
sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/conf.d/example.com.conf
sudo nginx -t
Ubuntu 执行:
sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/example.com.conf
sudo nginx -t
预期输出(两者相同):
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
第4步:配置SSL反向代理到后端应用
生成自签名证书(生产环境请用Let's Encrypt):
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048
-keyout /etc/nginx/ssl/example.com.key
-out /etc/nginx/ssl/example.com.crt
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com"
预期输出:
Generating a RSA private key
.............................+++++
.......................................+++++
writing new private key to '/etc/nginx/ssl/example.com.key'
-----
创建反向代理配置:
sudo tee /etc/nginx/sites-available/api-proxy.conf <<'EOF'
upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 backup;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
client_max_body_size 50M;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
proxy_send_timeout 300s;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_buffering off;
proxy_request_buffering off;
}
location /metrics {
proxy_pass http://127.0.0.1:9090/metrics;
proxy_set_header Host $host;
}
}
server {
listen 80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
EOF
预期输出:
server {
listen 443 ssl http2;
server_name api.example.com;
...
}
⚠️ 警告:启用新配置前务必执行测试!
sudo ln -s /etc/nginx/sites-available/api-proxy.conf /etc/nginx/sites-enabled/api-proxy.conf
sudo nginx -t && echo "配置语法正确"
预期输出:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
配置语法正确
第5步:配置负载均衡(upstream)
创建负载均衡配置:
sudo tee /etc/nginx/sites-available/loadbalancer.conf <<'EOF'
upstream web_cluster {
least_conn;
server 10.0.1.10:8000 weight=5 max_fails=2 fail_timeout=10s;
server 10.0.1.11:8000 weight=3 max_fails=2 fail_timeout=10s;
server 10.0.1.12:8000 weight=2 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8000 backup;
}
server {
listen 80;
server_name lb.example.com;
location / {
proxy_pass http://web_cluster;
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_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 10s;
}
location /status {
proxy_pass http://web_cluster;
access_log off;
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/loadbalancer.conf /etc/nginx/sites-enabled/loadbalancer.conf
sudo nginx -t
预期输出:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
第6步:配置限流防止滥用
创建限流配置:
sudo tee /etc/nginx/sites-available/rate-limit.conf <<'EOF'
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
listen 80;
server_name limit.example.com;
root /var/www/limit.example.com/html;
location /api/ {
limit_req zone=api_limit burst=200 nodelay;
proxy_pass http://backend;
proxy_set_header Host $host;
}
location /auth/login {
limit_req zone=login_limit burst=10 nodelay;
limit_conn conn_limit 5;
proxy_pass http://backend;
limit_req_status 429;
limit_conn_status 429;
}
error_page 429 = @rate_limit_exceeded;
location @rate_limit_exceeded {
return 429 '{"error":"rate_limit_exceeded","retry_after":60}';
add_header Content-Type application/json;
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/rate-limit.conf /etc/nginx/sites-enabled/rate-limit.conf
sudo nginx -t
预期输出:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
第7步:配置日志轮转与性能调优
创建日志轮转配置:
sudo tee /etc/logrotate.d/nginx <<'EOF'
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
EOF
cat /etc/logrotate.d/nginx
预期输出:
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
调优系统内核参数(添加到 /etc/sysctl.conf):
sudo tee -a /etc/sysctl.conf <<'EOF'
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
fs.file-max = 1000000
EOF
sudo sysctl -p
预期输出:
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
fs.file-max = 1000000
第8步:平滑reload验证所有配置
执行reload:
sudo nginx -s reload
sleep 1
sudo nginx -v && ps aux | grep nginx | grep -v grep
预期输出:
nginx version: nginx/1.20.1
root 12345 0.0 0.2 12345 4567 ? Ss 10:00 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
www-data 12346 0.0 0.1 12356 2345 ? S 10:00 0:00 nginx: worker process
www-data 12347 0.0 0.1 12356 2346 ? S 10:00 0:00 nginx: worker process
www-data 12348 0.0 0.1 12356 2347 ? S 10:00 0:00 nginx: worker process
www-data 12349 0.0 0.1 12356 2348 ? S 10:00 0:00 nginx: worker process
检查所有站点配置加载情况:
sudo nginx -T 2>&1 | grep -E "server_name|listen" | head -30
预期输出:
listen 80;
server_name example.com www.example.com;
listen 443 ssl http2;
server_name api.example.com;
listen 80;
server_name api.example.com;
listen 80;
server_name lb.example.com;
listen 80;
server_name limit.example.com;
三、常见问题FAQ
Q1:配置reload了但完全不生效,curl返回的还是旧内容?
老手回答:先确认你改的不是include进来的文件里的错误路径,其次检查proxy_cache有没有缓存。直接curl -I 看一下响应头里的Cache-Control和X-Cache-Status。另外还有个坑——如果你在server块里用了set $var "xxx",但这个变量在location里没被引用,Nginx会把它优化掉根本不执行。排查命令:nginx -T | grep -A5 'location /your_path'。
Q2:upstream后端明明是通的,但Nginx报502 Bad Gateway?
老手回答:别上来就怀疑Nginx配置,大概率是后端应用的问题。用curl直连后端地址看能不能返回,再看后端日志。常见坑:后端监听的端口绑定了127.0.0.1但你的proxy_pass写的公网IP、后端进程OOM被OOM Killer干掉了、后端用的是Unix Socket但权限不对。调试命令:netstat -tlnp | grep 8080 看端口监听状态,tail -f /var/log/nginx/error.log 看实时错误日志。
Q3:CPU占用率飙到100%,Nginx worker进程全卡住?
老手回答:十有八九是惊群问题或者没开worker_connections导致的。更恶心的是upstream keepalive没配对——Nginx侧设置了keepalive但后端没开启长连接,每次请求都要走三次握手。另一个常见场景是regex location匹配了带参数的请求,正则回溯导致CPU 100%。先执行top -H -p $(pgrep -d',' nginx)看看是哪个worker占用高,然后用strace -p pid -f -T看看卡在哪。
Q4:同一个IP访问量正常但带宽打满了,怀疑被恶意爬虫?
老手回答:先用awstats或者goaccess分析access日志,确认是哪个URL消耗带宽。如果是大文件下载类站点,配置下proxy_cache_range,不然每次请求都透传到后端。很可能是CSS/JS/图片没做压缩或没开启gzip,或者被人镜像了你的站点。配置gzip_static可以减少压缩CPU消耗。恶意爬虫的话,limit_req和limit_conn先怼上去,然后分析日志把异常IP加入iptables的recent模块黑名单。
Q5:HTTPS配置了但Chrome还是显示不安全?
老手回答:检查证书链是否完整——用openssl s_client -connect yourdomain.com:443 -showcerts看看返回的证书链有没有中间证书。另外检查SNI是否启用,很多CDN或者负载均衡器会改掉SNI头导致证书匹配失败。还有个老坑:mixed content,页面里引用了http://的资源,浏览器会降级显示不安全。用curl -k可以绕过证书验证,但线上别用-k参数排查。
四、总结
核心要点:
- 生产环境必须分离配置:站点配置放sites-available/sites-enabled或conf.d/,不要全塞nginx.conf
- reload前必须nginx -t验证语法,配置错了不会回滚,只会让你半夜爬起来
- 反向代理必须设置X-Forwarded-*系列请求头,不然后端拿不到真实客户端IP
- upstream的backup参数只用于故障转移,不是负载分担,权重weight才是分担
- 限流配置要分场景:API接口用r/s,后台登录用r/m,防止暴力破解
- 所有配置修改完成后立即检查ps aux | grep nginx确认进程存活
延伸阅读:
最后说一句:Nginx配置这东西,文档看一百遍不如线上踩一个坑。记住生产环境改配置前先备份nginx.conf,改完后立刻reload并检查进程状态,别等到用户投诉了才发现。