前言 一、配置 1. 配置实例 1.1. 80端口转443 1 2 3 4 5 server { listen 80 default_server; listen [::]:80 default_server; rewrite ^ https://$http_host$request_uri? permanent; }
1.2. 请求url代理到另一个地址 proxy_pass会自动将get参数和post参数带到代理的地址去,不需要加上$query_string
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 location /test { # 代理地址如果不带后面地址,将会请求 http://127.0.0.1:1234/test proxy_pass http://127.0.0.1:1234; # 代理地址如果带后面地址,将会请求 http://127.0.0.1:1234/aaa proxy_pass http://127.0.0.1:1234/aaa; } # 假设请求的地址为 http://x.x.x.x/test/bbb location /test/ { # 代理地址如果不带后面地址,将会请求 http://127.0.0.1:1234/test/bbb proxy_pass http://127.0.0.1:1234; # 代理地址如果带后面地址,将会请求 http://127.0.0.1:1234/aaabbb # 由于location加了/,proxy_pass会删除/test/,剩下bbb拼接到后面url proxy_pass http://127.0.0.1:1234/aaa; # 代理地址如果带后面地址,将会请求 http://127.0.0.1:1234/aaa/bbb proxy_pass http://127.0.0.1:1234/aaa/; }
1.3. 支持websocket 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 map $http_upgrade $connection_upgrade { default keep-alive; #默认为keep-alive 可以支持 一般http请求 'websocket' upgrade; #如果为websocket 则为 upgrade 可升级的。 } ... server { listen 8002; listen [::]:8002; server_name localhost; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }
1.4. 配置tcp代理 需要使用stream
模块 下面配置将本地8888的tcp代理到外部8889,可以通过0.0.0.0:8889
访问到127.0.0.1:8888
1 2 3 4 5 6 7 8 9 10 11 12 stream { upstream tcpServer { server 127.0.0.1:8888; } server { listen 8889; proxy_pass tcpServer; proxy_connect_timeout 10s; proxy_timeout 24h; } }
1.5. root和alias root可以配置到http
、server
、location
alias只能配置到location
root配置访问的是 root + location
alias访问的只有 alias
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 location /test { # 请求http://x.x.x.x/test 访问 /var/www/html/test # 请求http://x.x.x.x/test/ 访问 /var/www/html/test/ root /var/www/html; # 请求http://x.x.x.x/test 访问 /var/www/html # 请求http://x.x.x.x/test/ 访问 /var/www/html/ alias /var/www/html; # 请求http://x.x.x.x/test 访问 /var/www/html/ # 请求http://x.x.x.x/test/ 访问 /var/www/html// alias /var/www/html/; } location /test/ { # 请求http://x.x.x.x/test 无法访问 # 请求http://x.x.x.x/test/ 访问 /var/www/html/test/ root /var/www/html; # 请求http://x.x.x.x/test/aaa 访问 /var/www/htmlaaa alias /var/www/html; # 请求http://x.x.x.x/test/aaa 访问 /var/www/html/aaa alias /var/www/html/; }
1.6. 反向代理 keepalive为每个工作进程中缓存的到上游的空闲保持连接的最大数量,超过会关闭最近最少使用的连接 1 2 3 4 5 6 7 8 9 10 11 12 13 14 upstream http_proxy { server 127.0.0.1:8080; keepalive 16; } server { ... location / { proxy_pass http://http_proxy; proxy_http_version 1.1; proxy_set_header Connection ""; } }
2. 安全配置 限制不安全请求方法,拒绝接受除POST和GET,HEAD以外的请求方法
1 2 3 if ($request_method !~ ^(GET|POST)$ ) { return 405; }
去除nginx指纹信息
1 2 server_tokens off; proxy_hide_header X-Powered-By; #隐藏powered-by,如果使用反向代理,也可以通过 proxy_hide_header 指令隐藏它
防止溢出,给所有客户端配置buffer容许最大值
1 2 3 4 client_body_buffer_size 1K; client_header_buffer_size 1k; client_max_body_size 1k; large_client_header_buffers 2 1k;
控制iframe,防止iframe注入
1 add_header X-Frame-Options SAMEORIGIN; #设置iframe内容必须同源
XSS防护配置
1 2 add_header X-XSS-Protection "1; mode=block"; #启用内置XSS filter add_header Content-Security-Policy "default-src 'self'; img-src 'self' *.alicdn.com; object-src 'none'; script-src 'self' *.alicdn.com; style-src 'self' *.alicdn.com; frame-ancestors 'self'; base-uri 'self'; form-action 'self'"; #启用内容安全策略,减少XSS攻击
限制仅使用HTTPS访问
1 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; #(HSTS) 告诉浏览器该站点只能通过 HTTPS 访问,如果使用了子域,也建议对任何该站点的子域强制执行此操作。
cookie信息安全
1 2 add_header Set-Cookie "Path=/; HttpOnly; Secure"; proxy_cookie_path / "/; httponly; secure; SameSite=None"; #反向代理时要设置参数解决Cookie跨域丢失
跨域请求设置
1 2 3 4 5 6 7 8 9 10 11 12 13 # 通过配置Access-Control-Allow-Origin参数可以指定哪些域可以访问你的服务器,这个值要么是* 要么是带协议端口号确定的值, *.xx.com都是错误的值。 *.xx.com set $cors ""; if ($http_origin ~* (.*\.atpool.com)) { set $cors $http_origin; } add_header Access-Control-Allow-Origin $cors; add_header Access-Control-Allow-Methods "GET,POST,OPTIONS,DELETE,PUT"; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Headers *; if ($request_method = "OPTIONS") { return 204; }
加密与证书设置
1 2 3 4 5 6 7 8 # 只容许TLS1.2及以上版本,加密算法只容许强加密算法 ssl_certificate cert/xx.com.pem; ssl_certificate_key cert/xx.com.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; # 只启用TLS1.2 以上 ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on;
禁止nginx服务器目录列表功能
3. 配置详解 3.1. 反向代理配置 配置代理请求缓存,如果为on,nginx会将代理过程中的数据做缓存,缓存到proxy_temp
目录下 此配置和配置到http/server/location中 处理的是单个连接中,如果上下游速度不匹配而导致的数据可以进行缓存,加快上游或下游的写包速度,而非缓存用于同样请求的响应 1 2 proxy_request_buffering off; # 关闭代理请求缓存 proxy_buffering off; # 关闭代理响应缓存
3.2. so_keepalive keepalive配置 1 2 3 server { listen 80 so_keepalive=2m:10s:3; }
为连接保持的设置,上面配置连接空闲2min后发送keepalive包,间隔10s发一次,3次没有响应连接关闭 3.3. proxy_ssl_protocols 配置代理的ssl版本 1 2 3 4 Syntax: proxy_ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3]; Default: proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; Context: http, server, location
TLSv1.3仅在nginx版本1.23.4之后作为默认值 3.4. 日志 访问日志access.log
中的时间是响应的时间,不是请求的时间 二、命令详解 1. 常用命令 2. 配置检查 1 2 3 4 => nginx -t 2022/09/01 00:49:22 [warn] 4992#4992: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size 2022/09/01 00:49:22 [emerg] 4992#4992: "types_hash_max_size" directive is not allowed here in /etc/nginx/nginx.conf:144 nginx: configuration file /etc/nginx/nginx.conf test failed
三、openrestry OpenResty 的核心和精髓:cosocket
1. 和nginx的区别 OpenResty(也称为 ngx_openresty)是一个全功能的 Web 应用服务器。它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。
通过揉和众多设计良好的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的 Web 应用服务器,基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种 Nginx C 模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用。
2. 安装和运行 2.1. docker 1 docker pull openresty/openresty
1) 运行 1 docker run -p 8080:80 -p 443:443 -d -i openresty/openresty
2) 开发 1 2 3 4 5 6 7 8 9 10 11 mkdir -p ./usr/local/openresty/nginx # openresty配置 docker cp openresty:/usr/local/openresty/nginx/conf ./usr/local/openresty/nginx # 静态界面 docker cp openresty:/usr/local/openresty/nginx/html ./usr/local/openresty/nginx # logs docker cp openresty:/usr/local/openresty/nginx/logs ./usr/local/openresty/nginx mkdir -p ./etc # nginx配置 docker cp openresty:/etc/nginx ./etc
编辑一个openresty-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 version: '3' services: openresty: container_name: openresty image: 'openresty/openresty:latest' network_mode: 'host' volumes: - ./usr/local/openresty/nginx/conf:/usr/local/openresty/nginx/conf:rw - ./usr/local/openresty/nginx/html:/usr/local/openresty/nginx/html:rw - ./usr/local/openresty/nginx/logs:/usr/local/openresty/nginx/logs:rw - ./etc/nginx:/etc/nginx:rw tty: true privileged: false restart: always
1 docker-compose -f openresty-compose.yml up -d
3) lua支持 编辑/usr/local/openresty/nginx/conf/nginx.conf
1 2 3 4 5 6 7 8 9 10 11 http { # 在http块下添加下面的代码 lua_socket_read_timeout 5m; lua_code_cache on; # /usr/local/openresty/nginx/conf/lua/?.lua 自定义lua文件,使用require时,字符串会替换问号,所以只能有一个问号 # /usr/local/openresty/lualib/?.lua 系统的lua文件 lua_package_path '/usr/local/openresty/nginx/conf/lua/?.lua;/usr/local/openresty/lualib/?.lua;'; # 系统的lua的c库 lua_package_cpath '/usr/local/openresty/luajit/lib/?.so;/usr/local/openresty/luajit/lib/?.so;'; ... }
新增/usr/local/openresty/nginx/conf/lua/test.lua
写入如下内容 1 2 3 4 5 6 7 local _M = {}function _M:run () ngx.say("<p>hello, world</p>" ) end return _M
编辑/etc/nginx/conf.d/default.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 server { listen 80; server_name localhost; #charset koi8-r; location = /test { content_by_lua_block { local test = require "test" test.run() } } ... }
访问http://localhost/test
就能看到hello, world
了 3. 协程调度 3.1. ngx.thread 1) ngx.thread.spawn 看似是起了一个线程,实际上这个ngx.thread.spawn
是起了一个协程,这个协程是依托于主线程的,在主线程上同一时间只有一个协程在运行 使用cosocket或显式调用coroutine.yield()
才可以主动释放cpu,否则到哪个协程就会在这个协程一直跑下去 四、好用的第三方module https://github.com/alibaba/tengine.git
踩坑记 1. nginx启动报[emerg] bind() to 0.0.0.0:xxx failed (13: Permission denied)
出现问题的设备是centos7,默认开启了selinux,对http监听的端口有范围限制 如果是小于1024是需要使用root运行,大于1024参照下面方案 方案1 关闭selinux 1 2 3 4 # 查看selinux当前状态 getenforce # 设置selinux关闭 setenforce 0
方案2 使用semanage添加端口 1 2 3 4 5 # 查看支持的http端口列表 => semanage port -l | grep http_port_t http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000 # 添加端口 => semanage port -a -t http_port_t -p tcp 8090
2. nginx报[warn] 4992#4992: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
需要在http模块内部添加配置将types_hash_max_size
调大 1 2 3 4 http { types_hash_max_size 4096; ... }
3. nginx反向代理后time_wait过多存在问题 在upstream中添加keep_alive选项,可以在一个tcp连接发送多个http请求,防止tcp连接过多而time_wait状态太多造成端口不可用的问题 需要同时设置http版本为1.1,connection为空 1 2 3 4 5 6 7 8 9 10 11 12 13 14 upstream http_proxy { server 127.0.0.1:8080; keepalive 16; } server { ... location / { proxy_pass http://http_proxy; proxy_http_version 1.1; proxy_set_header Connection ""; } }