nginx 在 docker 中的编译与配置见 https://github.com/lanseyujie/docker-lnmp/tree/master/nginx
配置
http://nginx.org/en/docs/ngx_core_module.html
nginx.conf
# 运行的使用的用户和用户组 user nginx nginx; # 进程数,通常设置成 CPU 的核心数 worker_processes auto; # 全局错误日志 # 日志级别 # debug info notice warn error crit alert emerg error_log /var/log/nginx/error.log warn; # 进程文件,写有当前进程的 pid pid /var/run/nginx.pid; # 更改每个进程最大打开文件数 # 可以处理比 ulimit -n 更多的文件而不出现 too many open files worker_rlimit_nofile 51200; events { # 指定 I/O 模型 # epoll 是 Linux kernel 2.6 之后版本中的高性能网络 I/O 模型 # BSD 系列系统应使用 kqueue use epoll; # 单个进程最大连接数 worker_connections 51200; # 默认为禁用,此时一个进程只能同时接受一个新的连接。 # 否则一个进程可以同时接受所有的新连接 # kqueue 模型下会忽略此设置 multi_accept on; } http { # 文件扩展名与文件类型映射表 include /etc/nginx/mime.types; # 默认的 MIME 类型 default_type application/octet-stream; # 服务器名称 hash 表大小 server_names_hash_bucket_size 128; # 为请求头分配一个缓冲区 # 如果请求头大小超过设置值则使用large_client_header_buffers 分配更大的缓冲区 client_header_buffer_size 32k; # 用于读取大型客户端请求头的缓冲区的最大数量和大小 # 这些缓冲区仅在缺省缓冲区不足时按需分配 # 当处理请求或连接转换到保持活动状态时释放缓冲区 large_client_header_buffers 4 32k; # 用于设置请求正文的缓冲区大小 # 如果请求正文大小超过设定值且小于 client_max_body_size 则将其写入 client_body_temp 下的临时文件 client_body_buffer_size 10m; # 客户端请求服务器最大允许大小 # 如果请求头中 Content-Length 的大于此值将抛出 413 错误 client_max_body_size 1024m; # 启用数据在内核中的文件描述符之间传递,避免数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝 sendfile on; # 在一个数据包里发送所有头文件,而不一个一个的发送 # 必须与 sendfile 搭配使用 tcp_nopush on; # 不缓存数据,而是一段一段的发送 tcp_nodelay on; # 长连接超时时间,单位秒 keepalive_timeout 120; # 不显示 nginx 版本号 server_tokens off; # fastcgi 相关 fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 128k; fastcgi_intercept_errors on; # 开启 gzip 压缩 gzip on; # 压缩缓冲区数量和大小 gzip_buffers 16 8k; # 压缩级别,级别范围 1-9 gzip_comp_level 6; # 压缩版本 gzip_http_version 1.1; # 最小压缩文件大小 gzip_min_length 256; # 作为反向代理时会根据请求头中的 Via 字段判断是否压缩 # expired 当请求头中包含 Expires 头信息时启用压缩 # no-cache 当请求头中包含 Cache-Control:no-cache 头信息时启用压缩 # no-store 当请求头中包含 Cache-Control:no-store 头信息时启用压缩 # private 当请求头中包含 Cache-Control:private 头信息时启用压缩 # no_last_modified 当请求头中不包含 Last-Modified 头信息时启用压缩 # no_etag 当请求头中不包含 ETag 头信息时启用压缩 # auth 当请求头中包含 Authorization 头信息时启用压缩 # any 无条件启用压缩 # off 不启用压缩 gzip_proxied any; # 开启后会在响应头添加 Accept-Encoding:gzip gzip_vary on; # 除 html 外需要压缩的 MIME 类型 gzip_types text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml text/javascript application/javascript application/x-javascript text/x-json application/json application/x-web-app-manifest+json text/css text/plain text/x-component font/opentype application/x-font-ttf application/vnd.ms-fontobject image/x-icon; # 对 IE 6 及以下浏览器不使用压缩 gzip_disable "MSIE [1-6]\.(?!.*SV1)"; # 如果作为静态文件服务器,缓存文件的元数据而不是实际文件的内容会节省一些延迟 # max 设置最大缓存元素数,超出后使用 LRU 算法删除元素 # inactive 如果未设定时间内访问该元素则从缓存中删除,默认为 60s # off 禁用缓存 # open_file_cache max=1000 inactive=20s; # 缓存元素有效期,超过有效期将会重新检查元信息 # open_file_cache_valid 30s; # inactive 时间内文件最少使用次数,超过次数将继续标记元素为活动使用,否则将被从缓存中删除 # open_file_cache_min_uses 2; # 启用则缓存文件查找时的错误,而不再查找资源 # open_file_cache_errors on; include /etc/nginx/conf.d/http/*.conf; } stream { # include /etc/nginx/conf.d/stream/*.conf; }
虚拟主机配置
常规配置
server { listen 80; # listen 443 ssl http2; server_name localhost; # ssl_certificate /etc/nginx/ssl/fullchain.cer; # ssl_certificate_key /etc/nginx/ssl/cert.key; # ssl_protocols TLSv1.2 TLSv1.3; # ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; # ssl_prefer_server_ciphers on; # ssl_buffer_size 1400; # ssl_session_cache shared:SSL:10m; # ssl_session_timeout 10m; # ssl_session_tickets on; # note: openssl rand 48 > /etc/nginx/ssl/session_ticket.key # ssl_session_ticket_key /etc/nginx/ssl/session_ticket.key; # note: openssl s_client -connect example.com:443 -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response" # ssl_stapling on; # ssl_stapling_verify on; # ssl_trusted_certificate /etc/nginx/ssl/fullchain.cer; # resolver 8.8.4.4 8.8.8.8 valid=300s; # resolver_timeout 10s; # note: openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096 # ssl_dhparam /etc/nginx/ssl/dhparam.pem; charset utf-8; access_log /var/log/nginx/access.log combined; root /data/default; index index.html index.htm index.php; # if ($ssl_protocol = "") { # return 301 https://$host$request_uri; # } # error_page 404 /404.html; # error_page 500 /500.html; # error_page 502 /502.html; # error_page 504 /504.html; # note: HSTS (15768000 seconds = 6 months) # add_header Strict-Transport-Security "max-age=15768001; preload"; # add_header Cache-Control "no-cache, must-revalidate, max-age=60"; # add_header X-Content-Type-Options nosniff; # add_header X-Frame-Options SAMEORIGIN; # add_header Content-Security-Policy "default-src 'self'; script-src 'unsafe-inline':; style-src 'unsafe-inline'; img-src data:; media-src *;" # fastcgi_hide_header X-Powered-By; # location / { # try_files $uri $uri/ /index.php$is_args$args; # } # location / { # autoindex on; # autoindex_exact_size off; # autoindex_localtime on; # } # location / { # proxy_connect_timeout 20; # proxy_read_timeout 30; # proxy_send_timeout 30; # send_timeout 30; # proxy_redirect off; # 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_pass http://127.0.0.1:8080; # proxy_intercept_errors on; # } location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; } # location ~ [^/]\.php(/|$) { # note: comment here if you use path info # try_files $uri =404; # fastcgi_pass php:9000; # fastcgi_index index.php; # include /etc/nginx/fastcgi.conf; # } location ~ .*\.(gif|jpg|jpeg|png|webp|bmp|ico|svg|mp3|mp4|mkv)$ { # valid_referers none blocked server_names ~\.google\. ~\.baidu\.; # if ($invalid_referer) { # return 403; # # rewrite ^/ http://domain/forbidden.png; # } expires 30d; access_log off; } location ~ .*\.(js|css)?$ { expires 30d; access_log off; } location ~.*.mp4$ { mp4; } # location /download { # internal; # # alias /data/download; # secure_link $arg_token,$arg_expires; # secure_link_md5 "$secure_link_expires$uri$remote_addr mySecret"; # if ($secure_link = "") { return 403; } # if ($secure_link = "0") { return 410; } # } location ~ /\. { deny all; } }
禁止使用IP访问
server { listen 80 default; # listen 443 ssl default; server_name _; # note: openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/default.key -out /etc/nginx/ssl/default.cer # ssl_certificate /etc/nginx/ssl/default.cer; # ssl_certificate_key /etc/nginx/ssl/default.key; return 444; }
负载均衡
upstream backend { hash $remote_addr consistent; server 192.168.1.2:9000; server 192.168.1.3:9000; server 192.168.1.4:9000; server 192.168.1.5:9000; } server { listen 9000; proxy_connect_timeout 5s; proxy_timeout 30s; proxy_pass backend; }
变量
http://nginx.org/en/docs/http/ngx_http_core_module.html
# nginx 所在主机的主机名 $hostname # nginx 版本号 $nginx_version # 进程号 $pid # 当前的时间,毫秒 $msec # 请求的主机,如 lanseyujie.com 或 10.0.0.2 $host # 当前请求的 root 或 alias 指令的值 $document_root # 与当前请求的 root 或 alias 指令的值相对应的绝对路径名 # 所有符号链接都解析为真实路径 $realpath_root # 接受请求的服务器名称 $server_name # 接受请求的服务器地址 $server_addr # 接受请求的服务器端口 $server_port # 协议版本,如 HTTP/1.1 $server_protocol # 请求协议,如 https $scheme # 如果使用了 ssl 则为 on,否则为空 $https # PROXY 协议头中的客户端地址 # 必须通过在 listen 指令中设置 proxy_protocol 参数来预先启用 PROXY 协议 $proxy_protocol_addr # PROXY 协议头中的服务器地址 $proxy_protocol_server_addr # PROXY 协议头中的服务器端口 $proxy_protocol_server_port # 客户端地址 $remote_addr # 客户端端口 $remote_port # Basic Auth 验证的用户名 $remote_user # 请求速率限制 $limit_rate # 完整的原始请求行 $request # 获取一个请求头字段 # 字段名称为小写字母,并用 _ 代替 - $http_[header] # 请求方式,如 POST $request_method # 请求头中的 Content-Length 字段 $content_length # 请求头中的 Content-Type 字段 $content_type # 获取 cookie 中的一个字段值 $cookie_[name] # 请求中带有 GET 参数其值为 ?,无则为空 $is_args # GET 请求参数,如 id=2&type=3 $args # 获取一个 GET 参数的值 # 如请求参数为 id=2&type=3,则 $arg_id 为 2 $arg_[parameter] # 同 $args $query_string # 生成 16 位十六进制随机字节的唯一请求标识符 $request_id # 原始 URI,如 /member/profile?id=1&type=2 $request_uri # 不带参数的 URI,如 /member/profile # 可能会在请求处理期间更改,例如在进行内部重定向或使用索引文件时 $uri # 同 $uri $document_uri # 请求正文 # 当请求正文被读到内存缓冲区时,该变量在 proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass 指令中可用 $request_body # 带有请求正文的临时文件的名称 $request_body_file # 当前请求的文件路径 # 由 root 或 alias 和 URI 构成 $request_filename # 从客户端读取第一个字节以来经过的时间,单位:毫秒 $request_time # 发送给客户端的字节数 $bytes_sent # 发送给客户端的字节数,不计算响应头 $body_bytes_send # 获取一个响应头字段 # 字段名称为小写字母,并用 _ 代替 - $sent_http_[header] # 在响应末尾发送的任意字段 # 字段名称为小写字母,并用 _ 代替 - $sent_trailer_[header] # 响应状态 $status # 如果请求已完成则为 OK,否则为空 $request_completion
语法
location [ = | ~ | ~* | ^~ ] uri { ... }
匹配类型
没有修饰符时,为前缀匹配,将匹配 URI 开头部分与规则相同的请求。
修饰符为 = 时,为精准匹配,若匹配到与规则完全一致的 URI,就停止查找并使用该 location。
修饰符为 ~ 时,为大小写敏感的正则匹配。
修饰符为 ~* 时,为大小写不敏感的正则匹配。
修饰符为 ^~ 时,非正则匹配,正则表达式无效。
匹配顺序
首先查找前缀匹配,为每个前缀匹配都匹配一遍,暂存这个 location 。
再查找精准匹配,如果匹配上就停止查找并使用该 location。
如果精准匹配没有匹配上,会按照如下步骤继续查找最长前缀匹配:如果最长前缀匹配有 ^~ 修饰符,会停止查找并使用该 location;如果没有使用 ^~ 修饰符,暂存这个 location 并且继续查找。
若有最长前缀匹配被暂存,会再查找是否有使用 ~ 或 ~* 修饰且符合规则的 location,若有将使用第一个匹配上 location,若没有则使用前面暂存的 location。
其他语法
set variable value:设置变量。
if (condition) {}:-f 检测文件存在;-d 检测路径存在;-e 检测文件、路径或符号连接存在;-x 检测可执行文件存在。
return code:结束规则执行并返回状态码。使用如 444 等非标准状态码可以不发送任何响应头来结束连接。
rewrite regexp replacement flag:重定向 URI,重写的表达式只对相对路径有效。
rewrite 中几种 flag 的释义:
break:停止 rewrite 检测,该句为 rewrite 的最终结果,不再进行 location 匹配。
last:停止 rewrite 检测,last 语句不一定是最终结果,要进行 location 匹配,重定向到相同的规则会导致死循环。
permanent:301 永久重定向到新 URL。
redirect:302 临时重定向到新 URL。