本文主要介绍 nginx server 虚拟服务器如何配置。其中包括的一些示例;我想要整理一份比较完整的配置说明,避免找寻资料的麻烦,也尽可能的保证本文的准确性,如有失误,请告知。
$ nginx -V
nginx version: nginx/1.17.3
built by gcc 8.3.0 (Debian 8.3.0-6)
built with OpenSSL 1.1.1c 28 May 2019
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads ...
其中可以看到 --prefix=/etc/nginx,nginx 安装时会把相关数据文件写入到该目录,如我们的配置文件 --conf-path。
每次更改 nginx 的配置文件,你需要执行以下操作:
#验证配置文件的正确性
$ nginx -t
#重新加载配置文件
$ nginx -s reload
这里推荐 nginx 的官方文档地址:http://nginx.org/en/docs/。
文档中涵盖了各个模块的配置用法,以及默认值,可以填写的上下文位置。nginx-module-doc
目前 nginx 支持多种服务类型:
http
mail
stream
google perftools
我们着重介绍 http 服务。其它服务基本知识点都会涵盖到。
安装完 nginx ,我们先来看一看 nginx 的默认配置 /etc/nginx/nginx.conf,当然可能与你的默认配置不同,不过大同小异:
###配置文件解读
#worker以什么身份运行
user nginx; // default nobody
#worker进程个数,一般为 CPU 个数,也可选 auto
worker_processes 1; # default 1
#每个worker可打开的描述符限制
worker_rlimit_nofile 8192;
#错误日志保存路径和级别
error_log /var/log/nginx/error.log warn;
#进程pid保存路径
pid /var/run/nginx.pid;
#指定dns服务器
resolver 10.0.0.1;
events {
#每个worker最大连接数
worker_connections 1024; # default 1024
}
#http 服务定义
http {
#加载 mime 类型
include /etc/nginx/mime.types;
#定义默认数据类型
default_type application/octet-stream;
#日志格式
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函数(zero copy 方式)来输出文件,如果磁盘IO重负载应用,可设置为off
sendfile on;
#此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
#tcp_nopush on;
keepalive_timeout 65;
#代理相关设置
#proxy_connect_timeout 90;
#proxy_read_timeout 180;
#proxy_send_timeout 180;
#proxy_buffer_size 256k;
#proxy_buffers 4 256k;
#proxy_busy_buffers_size 256k;
#proxy_temp_file_write_size 256k;
#tcp_nodelay on;
#gzip 压缩
#gzip on;
#加载其它配置,这样我们在 conf.d 下写的文件才会生效
include /etc/nginx/conf.d/*.conf;
}
加载配置 /etc/nginx/conf.d,才能让我们的配置生效:
#加载其它配置
include /etc/nginx/conf.d/*.conf;
###配置文件解读完毕
一般的,如果是小站点不用去修改默认配置。当流量到达一定程度,需要进行适当优化。
内置变量,nginx 各个模块都将请求的一些参数进行变量化,通过 $ + 变量名 即可使用。每个模块或多或少都有自己的变量。着重介绍下核心模块的内置变量:
# 通过arg_<name>的方式可取出相关参数,若请求 /foo?name=Tony&age=2,则 arg_name=tony arg_age=2
$arg_name
$args
# 客户端IP地址二进制
$binary_remote_addr
# 发送到客户端的字节数,不包括响应头
$body_bytes_sent
# 发送给客户端字节数
$bytes_sent
# 连接序列号
$connection
# 当前已经连接的请求书
$connection_requests
# Content-Length 请求头
$content_length
# Content-Type 请求头
$content_type
# cookie 名称
$cookie_name
# 当前请求的 root 或 alias 的值
$document_root
# 与 $uri 相同
$document_uri
# 优先级:请求行中的 host name,请求头中的 Host,请求匹配的 server name
$host
# host name
$hostname
# 任意请求头字段。变量名的最后一部分是转换为小写的字段名,用下划线替换破折号
$http_name
# 如果连接在 SSL 模式下运行,则为 on,否则为空字符串
$https
# ? 后如果请求行有参数,或者空字符串
$is_args
# 设置此变量可以限制响应速度
$limit_rate
# 当前时间(秒),分辨率为毫秒
$msec
# nginx 版本号
$nginx_version
# 当前 worker 进程号
$pid
# 如果是 pipelined 则为 p,否则为 .
$pipe
# 代理协议头中的客户端地址,否则为空字符串,代理协议之前必须通过在listen指令中设置 proxy_protocol 参数来启用
$proxy_protocol_addr
# 来自代理协议头的客户端端口,否则为空字符串,代理协议之前必须通过在listen指令中设置 proxy_protocol 参数来启用
$proxy_protocol_port
# 与 $args 相同
$query_string
# 与当前请求的 root 或 alias 指令值对应的绝对路径名,所有符号链接都解析为实际路径
$realpath_root
# 客户端地址
$remote_addr
# 客户端端口
$remote_port
# 使用 Basic auth 的用户名
$remote_user
# 完整的请求行
$request
# 请求体,当将请求体读入内存缓冲区时,proxy_pass、fastcgi_pass、uwsgi_pass和scgi_pass指令处理的位置可以使用变量的值
$request_body
# 具有请求主体的临时文件的名称
$request_body_file
# 如果请求完成则为 OK,否则为空
$request_completion
# 当前请求的文件路径,基于 root 或 alias 和请求 URI
$request_filename
# 由16个随机字节生成的惟一请求标识符,以十六进制表示
$request_id
# 请求长度(包括请求行、头和请求体)
$request_length
# 请求方法,如 GET 或 POST
$request_method
# 请求处理时间,从客户端读取第一个字节以来的时间
$request_time
# 若请求 /foo?a=1&b=2,则 request_uri=/foo?a=1&b=2
$request_uri
# 如 http 或 https
$scheme
# 任意响应报头字段,变量名的最后一部分是转换为小写的字段名,用下划线替换破折号
$sent_http_name
# 响应结束时发送的任意字段,变量名的最后一部分是转换为小写的字段名,用下划线替换破折号
$sent_trailer_name
# 接受请求的服务器的地址
$server_addr
# 接受请求的 server 名称
$server_name
# 接受请求的 server 端口
$server_port
# 请求协议,如 HTTP/1.0 或 HTTP/1.1 或 HTTP/2.0
$server_protocol
# 响应状态
$status
$tcpinfo_rtt,$tcpinfo_rttvar,$tcpinfo_snd_cwnd,$tcpinfo_rcv_space
# 本地时间ISO 8601标准格式
$time_iso8601
# 通用日志格式的本地时间
$time_local
# 若请求 /foo?a=1&b=2,则 uri=/foo
$uri
# 用户代理
$http_user_agent
# cookie
$http_cookie
你还可以通过自定义变量指令 set 进行变量的定义。
server 即虚拟服务,它用来描述我们站点一些访问规则。需要填写在 http 标签中,可定义多个,如:
http {
server {
...
}
server {
...
}
...
}
一个常见的 server 的定义:
resolver 10.0.0.1;
# 负载均衡
upstream dynamic {
zone upstream_dynamic 64k;
server backend1.example.com weight=5;
server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
server 192.0.2.1 max_fails=3;
server backend3.example.com resolve;
server backend4.example.com service=http resolve;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
# http服务
server {
listen 80;
server_name example.com www.example.com;
location / {
rewrite https://$host; # 重定向到https
}
}
# https 服务
server {
listen 443 ssl; # 监听端口
server_name example.com www.example.com; # 匹配域名
# ssl证书
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/cert.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 静态服务
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# 反向代理
location /api {
proxy_pass http://dynamic;
health_check;
}
}
下面就让我们来详细解释下。
http_upstream_module
http_upstream_module,upstream
说白了就是做负载均衡,它可以帮助我们定义一组相同服务的别名,如backend,当请求到来的时候可以通过相关策略帮我们选一组服务提供响应。
目前只能被 proxy_pass,fastcgi_pass,uwsgi_pass,scgi_pass,memcached_pass,grpc_pass 使用。
形式如下:
upstream <name> { # 命名
server <address> [parameters]; # 服务
server <address> [parameters];
...
}
[parameters] 参数可选以下值:
weight=number,default 1,设置 server 的权重
max_conns=number,default 0,限制 server 的活跃连接数,0 代表不限制
max_fails=number,default 1,设置在 fail_timeout 时间内失败的最大次数,可由 proxy_next_upstream,fastcgi_next_upstream,uwsgi_next_upstream,scgi_next_upstream,memcached_next_upstream,grpc_next_upstream 指定下组 upstream,0 值代表不启用
fail_timeout=time,default 10s,设置多长时间判定无连接服务器失败
backup,标记 server 为备用 server,当 primary server 不可用时启用
down,标记 server 下线不可用
resolve,用来监视与服务器域名对应IP地址的更改,它会自动更改上游配置,upstream 必须驻留在共享内存中,必须写在 http 标签中。
http {
resolver 10.0.0.1;
upstream u {
zone ...;
...
server example.com resolve;
}
}
route=string,设置 server 路由名称 server=name, slow_start=time,慢启动,server 非正常状态恢复到正常需要的时间 drain,设置为 drain 模式
其它负载均衡设置:
zone name [size],设置共享内存的名称和大小 state file, hash key [consistent],负载均衡方式,key 可以为文本,变量,或其组合 ip_hash,负载均衡方式,根据IP地址范围分布 server,用 IPv4 前三个8位或整个IPv6 keepalive connections,设置到上游 server 保持最大空闲连接
upstream memcached_backend {
server 127.0.0.1:11211;
server 10.0.0.2:11211;
keepalive 32;
}
server {
...
location /memcached/ {
set $memcached_key $uri;
memcached_pass memcached_backend;
}
}
keepalive_requests number,设置最大请求连接数 keepalive_timeout timeout,连接超时时间 ntlm,允许使用NTLM身份验证代理请求
upstream http_backend {
server 127.0.0.1:8080;
ntlm;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}
least_conn,负载均衡方式,将请求传给活跃连接数最少的 server least_time header | last_byte [inflight],负载均衡方式,将请求传给平均响应时间和活跃连接数最少的 server queue number [timeout=time],队列缓存,当选择不到 server 处理请求时放入队列,如果队列满,返回502 random [two [method]],负载均衡方式, sticky,会话关联,同一客户端请求将会被传给同一 upstream 的同一 server
# cookie
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
# route
map $cookie_jsessionid $route_cookie {
~.+\.(?P<route>\w+)$ $route;
}
map $request_uri $route_uri {
~jsessionid=.+\.(?P<route>\w+)$ $route;
}
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
# learn
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8081;
sticky learn
create=$upstream_cookie_examplecookie
lookup=$cookie_examplecookie
zone=client_sessions:1m;
}
listen listen 监听设置,来看一看可选参数:
默认 listen *:80 | *:8000;
listen address[:port] [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen port [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen unix:path [default_server] [ssl] [http2 | spdy] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
真的多,可平时也没用几个,举例:
listen 127.0.0.1:8000;
listen 127.0.0.1; # 如果只指定地址,默认监听 80
listen 8000;
listen *:8000;
listen localhost:8000;
listen 127.0.0.1 default_server accept_filter=dataready backlog=1024;
# IPv6
listen [::]:8000;
listen [::1];
# unix socket
listen unix:/var/run/nginx.sock;
其它参数说明:
default_server,如果指定,server 将会成为默认 server
ssl,开启 ssl 模式,即 https
http2,正常情况开启 http2 都应该开始 ssl,但 nginx 也支持不开启 ssl 下的 http2 协议
spdy,和 http2 一样,建议开启 ssl
setfib=number,监听套接字设置关联的路由表FIB (SO_SETFIB选项)。这目前只适用于FreeBSD
fastopen=number,为监听套接字启用“TCP Fast Open”(1.5.8),并限制尚未完成三方握手的连接队列的最大长度
backlog=number
rcvbuf=size,接受 buffer 的大小(SO_CRCVBUF)
sndbuf=size,发送 buffer 的大小(SO_SNDBUF)
accept_filter=filter,可选 dataready 和 httpready,在 accept() 前过滤
deferred,指示在Linux上使用deferred accept() (TCP_DEFER_ACCEPT套接字选项)
bind,标记指定 address:port 单独的绑定
ipv6only on|off,只接受 IPv6 连接
reuseport
so_keepaliv on|off|[keepidle]:[keepintv1]:[keepcnt],”TCP keepalive” 开关
server_name server_name,设置虚拟主机的名称。
形式如下:
默认值 server_name "";
server_name name ...;
例1,穷举域名
server {
server_name example.com www.example.com;
}
例2,通配符写法
server {
server_name example.com *.example.com www.example.*;
}
例3 这种写法满足例1
server {
server_name .example.com;
}
例4 正则表达式,以 ~ 开头
server {
server_name www.example.com ~^www\d+\.example\.com$;
}
例5 正则表达式捕获
server {
server_name ~^(www\.)?(.+)$;
location / {
root /sites/$2;
}
}
server {
server_name _;
location / {
root /sites/default;
}
}
例6 正则表达式变量
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
root /sites/$domain;
}
}
server {
server_name _;
location / {
root /sites/default;
}
}
例7 与空名称使用
server {
server_name www.example.com "";
}
如果当一个名称匹配多个 server 的是时候,匹配优先级如下:
确切的名称
以 * 开头的最长的通配符名称
以 * 结尾的最长通配符名称
第一个匹配的正则表达式
更多匹配规则请查阅:http://nginx.org/en/docs/http/server_names.html
location location 是用来干嘛的,它是用来根据 URI 进行配置设置的,如:
server {
listen 80;
server_name example.com;
location / { # 普通请求网页
root /usr/share/nginx/html;
index index.html index.htm;
}
location /api { # API请求代理
proxy_pass http://dynamic;
health_check;
}
}
形式如下:
location [ = | ~ | ~* | ^~ ] uri { ... }
none,如果没有修饰符,则将该位置解释为前缀匹配。这意味着给定的位置将根据请求URI的开头进行匹配,以确定匹配
=,代表精确匹配,完全相等即匹配
~,区分大小写的正则表达式匹配
~*,不区分大小写的正则表达式匹配
^~,普通字符匹配,如果该选项匹配,只匹配该选项
nginx 的匹配过程如下:
精确匹配 =,如果匹配成功,搜索停止
前缀匹配,最长位置匹配,如果该匹配具有 ^~,搜索停止
正则匹配,按配置文件中定义的顺序进行匹配。
如果第3条规则产生匹配的话,结果被使用。否则,使用第2条规则的结果。
让我们通过一个例子来了解下匹配规则:
location = / {
[ configuration A ]
}
location / {
[ configuration B ]
}
location /documents/ {
[ configuration C ]
}
location ^~ /images/ {
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
[ configuration E ]
}
请求 / 将会匹配 A,请求 /index.html 将会匹配 B,请求 /documents/document.html 将会匹配 C,请求 /images/1.gif 将会匹配 D,请求 /documents/1.jpg 将会匹配 E。
ssl mode ssl 模式可以让我们站点启用 HTTPS,具体详细请参考 http_ssl_module。
想要开启 ssl 模式,需要在 listen 关键字处添加上 ssl,如:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate example.com.rsa.crt;
ssl_certificate_key example.com.rsa.key;
ssl_certificate example.com.ecdsa.crt;
ssl_certificate_key example.com.ecdsa.key;
...
}
上面的例子是部署双证书,当某一证书因某种原因失效不至于导致站点不能访问。下面来看看参数解释:
ssl_buffer_size size,default 16k,发送数据的缓冲区的大小
ssl_certificate file,PEM 格式证书文件
ssl_certificate_key file,PEM 格式私钥文件
ssl_ciphers ciphers,default HIGH:!aNULL:!MD5,ssl套件 openssl ciphers
ssl_client_certificate file,用于验证客户端证书的 CA 文件
ssl_crl file,用于验证客户端证书的吊销文件
ssl_dhparam file,为DHE密码指定具有DH参数的文件
ssl_early_data on|off,default on
ssl_ecdh_curve curve,default auto,为ECDHE密码指定一条曲线
ssl_password_file file,私钥密码文件
ssl_prefer_server_ciphers on|off,是否启用服务器套件偏好
ssl_protocols [SSLv2] [SSLv3] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3],default TLSv1 TLSv1.1 TLSv1.2,可选的ssl协议
ssl_session_cache off|none|[builtin[:size]] [shared:name:size],default none,设置 session cache 的类型和大小
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_session_ticket_key file,设置一个文件,其中包含用于加密和解密TLS会话票据的密钥
ssl_session_ticket_key current.key;
ssl_session_ticket_key previous.key;
随机一个 AES256(80),AES128(40)
openssl rand 80 > ticket.key
ssl_session_tickets on|off,default on,是否启用 session ticket
ssl_session_timeout time,default 5m,超时时间
ssl_stapling on|off,default off,ocsp 装订 ssl_stapling on; resolver 192.0.2.1;
ssl_stapling_file file
ssl_stapling_responder url
ssl_stapling_verify on|off,default off
ssl_trusted_certificate file,指定验证客户端证书的 CA 文件
ssl_verify_client on|off|optional|optional_no_ca,default off,是否验证客户端证书
ssl_verify_depth number,default 1,设置客户端证书链的验证深度
相关变量
$ssl_cipher,已建立连接使用的 ciphers
$ssl_ciphers,客户端支持的 ciphers
$ssl_client_escaped_cert,urlencoded 客户端证书
$ssl_client_fingerprint,SHA1指纹
$ssl_client_i_dn,issuer DN
$ssl_client_i_dn_legacy,同上,1.11.6之后使用
$ssl_client_raw_cert,PEM格式客户端证书
$ssl_client_s_dn,subject DN
$ssl_client_s_dn_legacy,同上,1.11.6之后使用
$ssl_client_serial,客户端证书序列号
$ssl_client_v_end,客户端证书结束时间
$ssl_client_v_remain,剩余多少天
$ssl_client_v_start,证书开始时间
$ssl_client_verify,客户端证书是否验证成功,"SUCCESS" 或 "FAILED:reason" 或 "NONE"
$ssl_curves,客户端支持的曲线
$ssl_early_data
$ssl_protocol,连接使用的协议
$ssl_server_name,从 SNI 获取的 server name
$ssl_session_id,连接的 session id
$ssl_session_reused,session是否重用,"r" 重用,"." 没有
其它模块 其它模块你需要根据文档及编译信息判断该模块是否默认编译在 nginx 中,并且版本是否匹配:
ngx_http_access_module
ngx_http_addition_module
ngx_http_api_module
ngx_http_auth_basic_module
ngx_http_auth_jwt_module
ngx_http_auth_request_module
ngx_http_autoindex_module
ngx_http_browser_module
ngx_http_charset_module
ngx_http_dav_module
ngx_http_empty_gif_module
ngx_http_f4f_module
ngx_http_fastcgi_module
ngx_http_flv_module
ngx_http_geo_module
ngx_http_geoip_module
ngx_http_grpc_module
ngx_http_gunzip_module
ngx_http_gzip_module
ngx_http_gzip_static_module
ngx_http_headers_module
ngx_http_hls_module
ngx_http_image_filter_module
ngx_http_index_module
ngx_http_js_module
ngx_http_keyval_module
ngx_http_limit_conn_module
ngx_http_limit_req_module
ngx_http_log_module
ngx_http_map_module
ngx_http_memcached_module
ngx_http_mirror_module
ngx_http_mp4_module
ngx_http_perl_module
ngx_http_proxy_module
ngx_http_random_index_module
ngx_http_realip_module
ngx_http_referer_module
ngx_http_rewrite_module
ngx_http_scgi_module
ngx_http_secure_link_module
ngx_http_session_log_module
ngx_http_slice_module
ngx_http_spdy_module
ngx_http_split_clients_module
ngx_http_ssi_module
ngx_http_ssl_module
ngx_http_status_module
ngx_http_stub_status_module
ngx_http_sub_module
ngx_http_upstream_module
ngx_http_upstream_conf_module
ngx_http_upstream_hc_module
ngx_http_userid_module
ngx_http_uwsgi_module
ngx_http_v2_module
ngx_http_xslt_module
nginx完整配置
一份给新人的 nginx 完整配置:https://github.com/deepzz0/nginx。
参考链接 [1] http://nginx.org/en/docs/