目录

编译安装

# 环境准备 Debian/Ubuntu 系统(旧版本的系统需要安装 libpcre3-dev)
sudo apt-get update
sudo apt-get install -y build-essential libssl-dev libpcre2-dev zlib1g-dev

# 编译,安装
cd /home/zmy/software/nginx/nginx-1.30.0
./configure \
  --prefix=/home/zmy/software/nginx/install \
  --with-http_ssl_module \
  --with-http_gzip_static_module
make
make install

# 更新
## 下载新版本
curl -O https://nginx.org/download/nginx-1.31.0.tar.gz
## 原编译参数
nginx -V
## 使用相同编译参数进行构建并编译
cd /home/zmy/software/nginx/nginx-1.30.0
./configure \
  --prefix=/home/zmy/software/nginx/install \
  --with-http_ssl_module \
  --with-http_gzip_static_module
make
## 备份旧的二进制文件
cp /home/zmy/software/nginx/install/sbin/nginx /home/zmy/software/nginx/install/sbin/nginx-1.30.0
## 替换二进制文件
cp objs/nginx /home/zmy/software/nginx/install/sbin/nginx

# 生成自签名证书
mkdir -p /home/zmy/software/nginx/install/conf/ssl
cd /home/zmy/software/nginx/install/conf/ssl

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout nginx.key \
  -out nginx.crt \
  -subj "/C=CN/ST=Jiangsu/L=Nanjing/O=Test/CN=zmy-aliyun" \
  -addext "subjectAltName=DNS:zmy-aliyun,DNS:localhost,IP:42.121.255.213,IP:127.0.0.1"
# 配置nginx
user  zmy;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      ssl/nginx.crt;
        ssl_certificate_key  ssl/nginx.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }

}
# 普通用户无法监听1024以下的端口,使用 setcap 赋予 nginx 二进制文件网络绑定能力
sudo setcap 'cap_net_bind_service=+ep' /home/zmy/software/nginx/install/sbin/nginx
# 如果依然无法监听1024以下端口,使用 root 运行,user 指令设置为 zmy
sudo /home/zmy/software/nginx/install/sbin/nginx

# 配置为服务 sudo 只让 cat 有了 root 权限去读,但后面的 > 写入文件 操作依然是以 zmy 身份尝试写入 /etc/...,而 zmy 没有权限写入该目录
sudo tee /etc/systemd/system/nginx.service > /dev/null <<EOF
[Unit]
Description=Nginx Service
Documentation=https://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/home/zmy/software/nginx/install/logs/nginx.pid

ExecStartPre=/home/zmy/software/nginx/install/sbin/nginx -t -c /home/zmy/software/nginx/install/conf/nginx.conf
ExecStart=/home/zmy/software/nginx/install/sbin/nginx -c /home/zmy/software/nginx/install/conf/nginx.conf
ExecStop=/home/zmy/software/nginx/install/sbin/nginx -s stop -c /home/zmy/software/nginx/install/conf/nginx.conf
ExecReload=/home/zmy/software/nginx/install/sbin/nginx -s reload -c /home/zmy/software/nginx/install/conf/nginx.conf

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

# 开机自启
sudo systemctl enable nginx

基础命令

🔥warning

使用正则表达式时,proxy_pass 中不可携带 uri (端口后的那部分路径)

配置文件

# nginx.conf 主配置文件结构
main上下文  # 全局配置
├── events上下文  # 事件模型配置
├── http上下文    # HTTP服务配置
│   ├── server上下文  # 虚拟主机配置
│   │   ├── location上下文  # URL匹配配置
│   │   └── location上下文
│   └── upstream上下文  # 负载均衡配置
└── stream上下文  # TCP/UDP代理配置
# 指令(指令名) 参数(值);
# ↓          ↓ ↓
  error_log  /var/log/nginx/error.log  info;
# 指令        参数1                    参数2

# 上下文指令(开启一个配置块)
events {
    # 块内指令
    worker_connections 1024;
}

main

events

events {
    # 关键参数
    worker_connections 1024;  # 最大连接数 = worker_processes * worker_connections
    
    # Linux优化
    use epoll;                # epoll(Linux)、kqueue(BSD)、select
    accept_mutex on;          # 避免"惊群"问题
    accept_mutex_delay 500ms;
    
    # 高性能配置
    multi_accept on;          # 一次接受所有新连接
    epoll_events 512;         # epoll事件数
}

http

http {
  include /etc/nginx/mime.types;  # MIME类型映射
  include /etc/nginx/conf.d/xxx.conf; # 包含自定义配置
  default_type application/octet-stream;  # 默认类型
  charset utf-8;  # 设置UTF-8编码

  # 定义日志格式和名字
  log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                   '"$http_user_agent" "$http_x_forwarded_for"';
  
  access_log /var/log/nginx/access.log main;  # 路径和格式
  
  # 基础配置
  sendfile on;              # 零拷贝传输
  tcp_nopush on;            # 优化数据包发送
  tcp_nodelay on;           # 禁用Nagle算法
  keepalive_timeout 65;     # 长连接超时
  types_hash_max_size 2048;

  # 缓冲区优化
  client_body_buffer_size 128k;
  client_max_body_size 10m;  # 最大上传文件大小
  client_header_buffer_size 1k;  # 请求头缓冲区大小
  large_client_header_buffers 4 8k;  # 4个8k缓冲区

  # 超时设置
  client_body_timeout 10s;
  client_header_timeout 10s;
  send_timeout 10s;

  # Gzip压缩
  gzip on;
  gzip_vary on;
  gzip_min_length 1k;
  gzip_types text/plain text/css application/json application/javascript; # 压缩类型
  gzip_comp_level 6;  # 1-9,数字越大压缩率越高
  gzip_min_length 1k;  # 只压缩大于1KB的文件
  gzip_vary on;  # 添加Vary: Accept-Encoding头

  # 缓存设置
  open_file_cache max=1000 inactive=20s;
  open_file_cache_valid 30s;
  open_file_cache_min_uses 2;
  open_file_cache_errors on;
}

server

location /image {
  root /opt/nginx/static;
}
# 当用户访问 www.test.com/image/1.png 时,实际在服务器找的路径是 /opt/nginx/static/image/1.png
location /image {
 alias /opt/nginx/static/image/;
}
# 当用户访问 www.test.com/image/1.png 时,实际在服务器找的路径是 /opt/nginx/static/image/1.png
ℹ️note
  • root 会将定义路径与 URI 叠加。如果locaiton没有指定,会往其外层的server或http中寻找继承。
  • alias 是别名,用于替换匹配的 uri,只能位于 location 中。
  • root 表示根路径,匹配的uri直接拼接在后面,多个斜杠等效于一个,所以root后加不加斜杠都可以
  • 实际使用保持匹配的 uri 后的斜杠与 alias 后的斜杠一致性。都有或都没有
  • ❌ 正则 location 中不能使用 root
location ~ ^/images/(.*\.(gif|jpg|jpeg))$ {
    alias /var/www/images/$1;  # 可以
    # root /var/www/images;  # 不行!
}
location /test {
 ...
}

location /test/ {
 ...
}
💡tip
  • 有反斜线则明确表示是一个目录,存在test目录则接着找index.html,不存在也不会去找是否有test文件
  • 没有反斜线,则表示是一个目录或者文件,如果存在test文件则返回,否则查找test目录,存在则接着找index.html,
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 365d;  # 长期缓存
    add_header Cache-Control "public, immutable";
    
    # 启用缓存
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    
    # 禁用访问日志,优化性能
    access_log off;
}

# ❌ 过多正则匹配影响性能
location ~* \.(jpg|jpeg|png|gif|ico|css|js|txt|xml|json|html|htm|php|pdf)$ {
    # 这个正则包含很多扩展名,每次请求都要匹配
}

# ✅ 优化:将静态文件分开
location ~* \.(css|js)$ {
    expires 1h;
}

location ~* \.(jpg|jpeg|png|gif|ico)$ {
    expires 30d;
}
return 404; # 直接返回状态码
return 404 "pages not found"; # 返回状态码 + 一段文本
return 302 /bbs ; # 返回状态码 + 重定向地址
return https://www.baidu.com; # 返回重定向地址
return 200 '{"status": "ok", "message": "Service is running"}'; # 返回json
return 200 '<!DOCTYPE html><html><body><h1>Custom HTML</h1></body></html>'; # 返回html
server {
  listen 80;
  server_name fe.lion-test.club;
  
  location /download/ {
    root /opt/source;
    
    autoindex on; # 打开 autoindex,,可选参数有 on | off
    autoindex_exact_size on; # 修改为off,以KB、MB、GB显示文件大小,默认为on,以bytes显示出⽂件的确切⼤⼩
    autoindex_format html; # 以html的方式进行格式化,可选参数有 html | json | xml
    autoindex_localtime off; # 显示的⽂件时间为⽂件的服务器时间。默认为off,显示的⽂件时间为GMT时间
  }
}

upstream

proxy_pass

# API代理
location /api/ {
  proxy_pass http://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_connect_timeout 30s;
  proxy_send_timeout 60s;
  proxy_read_timeout 60s;
  proxy_buffering on;
  proxy_buffer_size 4k;
  proxy_buffers 8 4k;

  # WebSocket支持
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
}
# 假设访问路径为 http://192.168.1.9/proxy/test.html
# 主机+端口类型
location  /proxy {
    proxy_pass http://127.0.0.1:81;
}
# 会被代理到http://127.0.0.1:81/proxy/test.html 这个url。

# 主机+端口+路径类型
location  /proxy {
    proxy_pass http://127.0.0.1:81/fly/;
}
# 会被代理到http://127.0.0.1:81/fly//test.html 这个url。  请注意这里的双斜杠。
💡tip
  • 无斜线直接将匹配的部分加在代理地址后面,有斜线则将匹配部分去掉再加到代理地址后面
  • 一般 location 后面的 uri 与 proxy_pass 后的斜线保持一致,以防出现双斜杠或无斜杠,即
location  /proxy/ {
    proxy_pass http://127.0.0.1:81/fly/;
}
# 代理到http://127.0.0.1:81/fly/test.html,把 test.html 拼到后面
location  /proxy {
    proxy_pass http://127.0.0.1:81/fly;
}
# 代理到http://127.0.0.1:81/fly/test.html,把 /test.html 拼到后面

配置缓存

配置https

server {
  listen 443 ssl http2 default_server;   # SSL 访问端口号为 443
  server_name lion.club;         # 填写绑定证书的域名(这里是随便写的)
  ssl_certificate /etc/nginx/https/lion.club_bundle.crt;   # 证书地址
  ssl_certificate_key /etc/nginx/https/lion.club.key;      # 私钥地址
  ssl_session_timeout 10m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 支持ssl协议版本,默认为后三个,主流版本是[TLSv1.2]
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # # 加密算法
  ssl_prefer_server_ciphers on; # 优先服务器选择的加密套件
  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 10m;
  
  # HSTS
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  
  # 其他安全头部  
  # 防止点击劫持
  add_header X-Frame-Options "SAMEORIGIN" always;

  # XSS防护
  add_header X-XSS-Protection "1; mode=block" always;

  # 禁止MIME类型嗅探
  add_header X-Content-Type-Options "nosniff" always;

  # 引用策略
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;

  # 内容安全策略
  add_header Content-Security-Policy "default-src 'self'" always;
  location / {
    root         /usr/share/nginx/html;
    index        index.html index.htm;
  }
}

调试配置

# 开启详细日志
error_log /var/log/nginx/error.log debug;

# 调试特定客户端
server {
    set $debug 0;
    if ($remote_addr = "192.168.1.100") {
        set $debug 1;
    }
    
    access_log /var/log/nginx/debug.log combined if=$debug;
}

# 验证配置文件
nginx -t
nginx -T  # 打印完整配置

是否加双引号

常见变量

请求行变量

变量名含义
request完整请求行:GET /api HTTP/1.1
server_protocol服务器协议:HTTP/1.0、HTTP/1.1
uri请求的 URI,只有路径,不包含参数
request_uri请求的 URI,包含参数
scheme协议名,http 或 https
request_method请求方法,GET、POST、PUT、DELETE等
args查询参数字符串:id=1&name=test
query_string与 args 相同
arg_参数名获取特定参数值
is_argsURI 中是否有参数,有的话返回 "?",否则返回空
host请求信息中的 Host,如果请求中没有 Host 行,则在请求头中找,最后使用 nginx 中设置的 server_name

请求头变量

变量名含义
http_*所有请求头,如$http_user_agent、$http_host
http_user_agent用户代理:Mozilla/5.0...
http_referer来源页面URL, 从哪些连接过来的请求
http_host请求的Host头
http_cookieCookie头
http_acceptAccept头
http_accept_languageAccept-Language头
http_accept_encodingAccept-Encoding头
http_content_typeContent-Type头
http_content_lengthContent-Length头
http_authorizationAuthorization头
http_via每经过一层代理服务器,都会添加相应的信息

连接信息

变量名含义
remote_addr客户端 IP 地址
remote_port客户端端口
remote_userBasic认证的用户名
server_addr服务端 IP 地址
server_port服务端端口
binary_remote_addr二进制格式的客户端 IP 地址
connectionTCP 连接的序号,递增
connection_requestTCP 连接当前的请求数量
https是否开启了 https,是返回 on,否则返回空

代理相关

变量名含义
proxy_protocol_addrPROXY协议传递的客户端IP
proxy_protocol_portPROXY协议传递的客户端端口
proxy_add_x_forwarded_for追加IP到X-Forwarded-For
proxy_hostproxy_pass指定的主机
proxy_portproxy_pass指定的端口

响应信息

变量名含义
status响应状态码:200、404、500等
body_bytes_sent发送给客户端的body字节数
bytes_sent发送的总字节数
senthttp*响应头,如$sent_http_content_type
sent_http_content_type响应Content-Type
sent_http_content_length响应Content-Length
sent_http_cache_control响应Cache-Control
request_length请求长度(包括请求行、头、体)
request_time请求处理时间(秒,毫秒精度)
upstream_response_time上游服务器响应时间
upstream_status上游服务器状态码
upstream_addr上游服务器地址
upstreamhttp*上游服务器的响应头
request_filename磁盘文件系统等待访问文件的完整路径

时间格式

变量名含义
time_iso8601ISO 8601格式:2023-12-20T10:30:00+08:00
time_local本地时间格式:20/Dec/2023:10:30:00 +0800
msec当前时间戳,毫秒:1703039400.123
request_time请求处理时间
upstream_response_time上游响应时间
upstream_connect_time上游连接时间
upstream_header_time上游接收头时间

文件路径

变量名含义
document_root当前请求的root/alias目录
realpath_root规范化后的$document_root
document_uri同$uri
request_filename请求的文件路径
fastcgi_script_nameFastCGI脚本名

条件变量

变量名含义
arg_*查询参数,如argidarg_id、arg_name
cookie_*Cookie值,如$cookie_session
http_*请求头
senthttp*响应头

SSL信息

变量名含义
ssl_protocolSSL/TLS协议版本:TLSv1.2
ssl_cipherSSL加密套件
ssl_client_s_dn客户端证书主题
ssl_client_i_dn客户端证书颁发者
ssl_client_verify客户端证书验证结果
ssl_session_idSSL会话ID
ssl_server_nameSNI服务器名称

其他

变量名含义
document_root由 URI 和 root/alias 规则生成的文件夹路径
limit_rate返回响应时的速度上限值