以前写过一篇类似的博文,之前的文章现在看起来逻辑有点混乱,当时用的是阿里云的红帽发行版本,现在空间不租了,我用 Mac 电脑又折腾了一遍,为了加深印象,我把过程记录下来。
简介 Nginx 是一个高性能的 HTTP 和 reverse proxy 服务器,同时也支持邮件代理。由俄罗斯程序员 Igor Sysoev 创建,目的为了解决 C10k 问题,即并发问题。在 2004 年 8 月 1 日首次发布。2019 年 3 月,Nginx 已经被 F5 公司收购。
Nginx 是一个轻量级的 Web 服务器,并且支持反向代理,负载均衡,HTTP 缓存,图片转换,静态内容加速等。在服务器市场占有率迄今为止是最高的。
安装
Linux
1 2 sudo apt update sudo apt install nginx
Mac OS
Windows
1 2 scoop install nginx choco install nginx
docker
启动
Linux,Mac OS
Windows 双击 nginx.exe
docker
1 docker run -d -p 8080:8080 nginx
浏览器打开:localhost:8080
验证是否启动成功:
第二栏就是 nginx 进程的 PID 53807 (Master) 和 53808 (Worker)
Nginx 的工作模式是主进程 Master - Worker 模式,主进程主要复制读取和验证配置文件,而 Worker 子进程负责处理请求。
查看 8080
端口占用情况:
常用命令
停止,重载及重新打开日志
上面的<signal>
可以是:
stop
:停止 Nginx
quit
:退出 Nginx
reload
:重载 Nginx 配置文件
reopen
:重新打开 Nginx 日志文件
查看 Nginx 各种配置参数
查看所有参数:nginx -V
,再看 --conf-path
参数的值
1 2 3 4 5 6 (base) zyzy:~ $ nginx -V nginx version: nginx/1.25.5 built by clang 15.0.0 (clang-1500.3.9.4) built with OpenSSL 3.2.1 30 Jan 2024 (running with OpenSSL 3.3.0 9 Apr 2024) TLS SNI support enabled configure arguments: --prefix=/opt/homebrew/Cellar/nginx/1.25.5 --sbin-path=/opt/homebrew/Cellar/nginx/1.25.5/bin/nginx --with-cc-opt='-I/opt/homebrew/opt/pcre2/include -I/opt/homebrew/opt/openssl@3/include' --with-ld-opt='-L/opt/homebrew/opt/pcre2/lib -L/opt/homebrew/opt/openssl@3/lib' --conf-path=/opt/homebrew/etc/nginx/nginx.conf --pid-path=/opt/homebrew/var/run/nginx.pid --lock-path=/opt/homebrew/var/run/nginx.lock --http-client-body-temp-path=/opt/homebrew/var/run/nginx/client_body_temp --http-proxy-temp-path=/opt/homebrew/var/run/nginx/proxy_temp --http-fastcgi-temp-path=/opt/homebrew/var/run/nginx/fastcgi_temp --http-uwsgi-temp-path=/opt/homebrew/var/run/nginx/uwsgi_temp --http-scgi-temp-path=/opt/homebrew/var/run/nginx/scgi_temp --http-log-path=/opt/homebrew/var/log /nginx/access.log --error-log-path=/opt/homebrew/var/log /nginx/error.log --with-compat --with-debug --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_v3_module --with-ipv6 --with-mail --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module
也可以用 nginx -t
查看
1 2 3 (base) zyzy:~ $ nginx -t nginx: the configuration file /opt/homebrew/etc/nginx/nginx.conf syntax is ok nginx: configuration file /opt/homebrew/etc/nginx/nginx.conf test is successful
一般来说,Mac 系统该配置文件在 /opt/homebrew/etc/nginx/nginx.conf
Linux 系统该配置文件在 /etc/nginx/conf
或 /usr/local/etc/nginx
配置 这个是 Nginx 的默认配置文件:默认很多操作没有解开:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } include servers/*; }
别看这么多,其实就 3 部分内容
全局块:例如worker_processes
配置 Nginx 的进程数,默认为 1;
events
:事件部分,配置 Nginx 的事件处理方式,如 worker_processes
、worker_connections
等
http
:HTTP 模块部分,配置 Nginx 的 HTTP 模块,如 server
、location
等
worker_processes
我们可以配置该参数为 auto
,这样就能自动匹配电脑应有的核心数。
这里我故意把配置写错:worker_processes 10
,尾部没加;
,运行 nginx -t
,能帮我们自带检查该文件错误:
1 2 3 (base) zyzy:1.25.5 (master) $ nginx -t nginx: [emerg] directive "worker_processes" is not terminated by ";" in /opt/homebrew/etc/nginx/nginx.conf:12 nginx: configuration file /opt/homebrew/etc/nginx/nginx.conf test failed
每次修改完成后,nginx -s reload
重新加载 nginx.conf
文件
改为 auto 后,跑 ps -ef | grep nginx
,发现 nginx
进程数变为 8 个,代表我用的 mac 电脑有 8 核,如下图:
events
worker_connections
:配置 Nginx 的最大连接数,默认为 1024multi_accept
:是否允许同时接受多个连接,默认为 off,表示只接受一个连接,如果为 on,则表示允许同时接受多个连接
http
这个是被修改得最多的模块
include mime.types
:包含 Nginx 能处理文件类型,默认为路径为: /opt/homebrew/etc/nginx/mime.types
server
在 http
模块下,包含多个 server
模块,每个 server
模块代表一个虚拟主机。
修改默认的 HTML 静态页面 部署一个静态站点,我们需要按以下配置修改对应的 html 文件:
1 2 3 4 location / { root html; index index.html index.htm; }
location /
:表示匹配所有请求,root
:表示静态资源文件存放的目录,index
:表示默认首页,默认为 index.html
那就去找这个 html
文件夹,可用 nginx -V
找到 --prefix=/opt/homebrew/Cellar/nginx/1.25.5
字段,能找到 Nginx 的安装路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 (base) zyzy:~ $ cd /opt/homebrew/Cellar/nginx/1.25.5 (base) zyzy:1.25.5 (master) $ ll total 680 -rw-r--r-- 1 ziyouzhiyi admin 319K 4 16 22:37 CHANGES -rw-r--r-- 1 ziyouzhiyi admin 1.3K 5 14 10:49 INSTALL_RECEIPT.json -rw-r--r-- 1 ziyouzhiyi admin 1.4K 4 16 22:37 LICENSE -rw-r--r-- 1 ziyouzhiyi admin 49B 4 16 22:37 README drwxr-xr-x 3 ziyouzhiyi admin 96B 5 14 10:49 bin -rw-r--r-- 1 ziyouzhiyi admin 685B 5 14 10:49 homebrew.mxcl.nginx.plist -rw-r--r-- 1 ziyouzhiyi admin 202B 5 14 10:49 homebrew.nginx.service lrwxr-xr-x 1 ziyouzhiyi admin 16B 5 14 10:49 html -> ../../../var/www drwxr-xr-x 4 ziyouzhiyi admin 128B 4 16 22:37 share (base) zyzy:1.25.5 (master) $ ls -ld $(readlink html) drwxr-xr-x 4 ziyouzhiyi admin 128 2 15 00:03 ../../../var/www (base) zyzy:1.25.5 (master) $ cd html (base) zyzy:html (master) $ ls 50x.html index.html
可以清晰的看到,html
不仅仅是一个软链接,他还是一个文件夹,Linux
和 MacOS
都可以将文件夹作为软链接,这样可以避免移动文件夹。
我们改动 index.html
,然后 nginx -s reload
重新加载配置,可以看到浏览器的页面已经修改:
1 2 3 (base) zyzy:1.25.5 (master) $ cd html (base) zyzy:html (master) $ ls 50x.html index.html
include servers/*;
:表示将 servers
目录下的所有配置文件包含进来
反向代理及负载均衡 写一个最简单的 node http 服务 index.js
1 2 3 4 5 6 7 8 9 10 11 12 const http = require ("http" );const PORT = 3000 ;const server = http.createServer((req, res ) => { res.writeHead(200 , { "Content-Type" : "text/html" }); res.write(`<h1>Node.js web server! Port: ${PORT} </h1>` ); res.end(); }); server.listen(PORT, () => { console .log(`Server is running on port ${PORT} ` ); });
我们将其复制 2 份,端口号分别改为 3020 和 3030,文件名改为 index-3000.js
,index-3020.js
,index-3030.js
,分别跑起来,页面localhost:3000
、localhost:3020
、localhost:3030
都能打开。
再修改 nginx.conf
,添加反向代理配置:http
模块中添加 upstream
反向代理字段, server 模块中添加 proxy_pass
字段,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 http { upstream backend { server 127.0.0.1:3000; server 127.0.0.1:3010; server 127.0.0.1:3020; } server { location /app { proxy_pass http://backend; } } }
重载 nginx -s reload
,然后访问 localhost:8080/app
,再不断刷新,页面显示如下,反向代理成功:
请求策略
upstream
字段下的 ip 地址,可以添加权重 weight
,如:
1 2 3 4 5 upstream backend { server 127.0.0.1:3000 weight=3; server 127.0.0.1:3010; server 127.0.0.1:3020; }
这样,我们多数的请求就会分配到端口为 3000 的服务器上,3000 的请求数量就会是其余两个的 3 倍。
1 2 3 4 5 6 upstream backend { ip_hash; server 127.0.0.1:3000; server 127.0.0.1:3010; server 127.0.0.1:3020; }
ip_hash
:根据客户端的 IP 地址进行哈希,同一个客户端的请求会分配到同一个服务器上,这样主要是解决 session 命中的问题。
SSL 配置 HTTPS 的安全层正数,可以在主流的云平台申请,我们也可以自己制作证书
生成密钥和证书 1 2 3 openssl genrsa -out private.key 2048 openssl req -new -key private.key -out cert.csr openssl x509 -req -in cert.csr -out cacert.pem -signkey private.key -days 3650
按照以上命令生成了 cacert.pem
(证书) 和 private.key
(私钥) 两个文件。将两个文件移动到 /opt/homebrew/etc/nginx/
目录下
1 (base) zyzy:1.25.5 (master) $ mv cacert.pem private.key /opt/homebrew/etc/nginx/
配置 nginx.conf 如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 server { listen 443 ssl; server_name localhost; ssl_certificate /opt/homebrew/etc/nginx/cacert.pem; ssl_certificate_key /opt/homebrew/etc/nginx/private.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; }
当我们访问 localhost:8080
,会发现 chrome 浏览器会提示我们不安全,这是因为证书是我们自己制作的,并非机构颁发,我们选择继续访问,并在这里可以点开查看我们刚刚输入的证书信息:
点击看到证书:
配置重定向 可以将 http 的访问重定向到我们的 https 端口上
1 2 3 4 5 server { listen 8080; server_name localhost; return 301 https://$host$request_uri ; }
如果有配置域名,则改为如下:
1 2 3 4 5 server { listen 8080; server_name zyzy.info; return 301 https://$server_name$request_uri ; }
虚拟主机 在网站初期,访问量较小,一个服务器配置多个服务可以节省资源,这种多服务器配置称为虚拟主机,下面我们来实现
server
独立配置我们将 /opt/homebrew/etc/nginx/nginx.conf
下上面配置好的 server
单独剪切出来,新建一个 localhost.conf
文件,放到 /opt/homebrew/etc/nginx/server
下,
重载 nginx -s reload
,浏览器打开发现网站正常运行,说明 server 目录可以存放多个虚拟主机的配置文件。
/nginx/server
下创建其他服务创建前端 SPA 页面 结合的 SPA 项目,我们用 vite 生成一个 react
项目,
1 2 3 4 npm create vite@latest demo-project -- --template react cd vite_reactnpm install npm run build
进入 dist 目录,复制路径:
1 2 (base) zyzy:dist $ pwd /Users/ziyouzhiyi/servers/demo-project/dist
创建server
模块 我们在 /opt/homebrew/etc/nginx/server
目录下写一个 vite_react.conf
配置文件,配置如下:将上面/Users/ziyouzhiyi/servers/demo-project/dist
路径配置如下:
1 2 3 4 5 6 7 8 9 server { listen 5173; server_name vite_react; location / { root /Users/ziyouzhiyi/servers/demo-project/dist; index index.html index.htm; } }
重载 nginx -s reload
检验配置 访问 localhost:5173
,页面正常显示,说明配置成功。页面访问:http://localhost:5173/
,如下:
上面的页面还没配置 ssl,我们把他改成 https 访问,将 localhost.conf,的配置粘过来,改动如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 server { listen 5173 ssl; server_name vite_react; ssl_certificate /opt/homebrew/etc/nginx/cacert.pem; ssl_certificate_key /opt/homebrew/etc/nginx/private.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; location / { root /Users/ziyouzhiyi/servers/demo-project/dist; index index.html index.htm; } }