Nginx + PM2 实现Express API + React 前端 本地测试服务器搭建
一、工具准备
openSSL:需要针对https请求头 生成对应的 自签名证书。
Nginx:服务器搭建工具
nodeJS: Express API运行环境
PM2: node进程管理器。用于替代npm命令管理 启动命令。
二、openSSL 本地自签名证书生成。
创建服务器空文件夹(这里可以和Nginx程序包位置在一起,也可以单独放置)例如:D:demo
在D:demo 文件夹 下创建 文件 generate_cert.sh
内容:
#!/bin/bashmkdir -p cert && cd certopenssl req -x509 -nodes -days 365 -newkey rsa:2048 \\ -keyout server.key -out server.crt \\ -subj \"/C=CN/ST=Beijing/L=Beijing/O=LocalDev/CN=localhost\"
执行这个sh,
或者创建 cert文件夹,cmd命令执行命令
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \\ -keyout server.key -out server.crt \\ -subj \"/C=CN/ST=Beijing/L=Beijing/O=LocalDev/CN=localhost\"
win系统文件权限问题可能导致 sh执行生成文件夹和文件失败。
这样就生成了这两个自签名文件,可以支持本地的https请求头使用。(浏览器访问会出现不安全提示,需要保存到本地系统可信任证书列表中)
三、Express API 相关配置、程序启动和PM2管理
拷贝Express API 程序到 D:demo 文件夹 下。
相关配置修改(例如环境变量中 环境参数改为生产环境对应值)
ssl相关内容也要配置修改
Express API 程序中 拷贝一份cert 文件夹到程序根目录
app.js入口文件中配置
...const keyPath = path.join(__dirname, \'../cert/localhost+3-key.pem\');const certPath = path.join(__dirname, \'../cert/localhost+3.pem\');const options = { key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath)};... // 创建HTTPS服务器 https.createServer(options, app).listen(process.env.API_PORT, () => { ... console.log(`Server running on https://localhost:${process.env.API_PORT}`); });
项目根目录下添加ecosystem.config.cjs 文件用于PM2 启动参数配置
module.exports = { apps: [ { name: \'PM2启动进程别名\', script: \'./dist/app.js\', type: \'module\', // 启用ES模块支持 watch: false, env: { //PM2启动默认设置环境变量 } } ]}
cd 到 API程序根目录下 cmd npm run build (package.json 配置的编译命令 其实就是 tsc 命令)
D:demo/API/项目根目录下 会生成一个dist编译后的包。
然后执行 pm2 start \"D:\\demo\\API\\ecosystem.config.cjs\" 命令(win 需要使用绝对路径)
启动程序
pm2 ls 可以看到 全部的 已管理的 node服务进程,
常用命令 pm2 logs 、pm2 stop 、 pm2 save
到这一步 Express API 本地 服务就搭建好了可通过https://localhost:端口号/路由地址
的方式访问API接口。
四、React 前端 Nginx 服务发布
https://localhost:端口号/路由地址react 前端程序 通过本地 环境 修改配置 适配 生产环境(例如:代理的API链接直接连接刚刚发布的API连接。还有一些 生产环境变量变动)
运行 npm run build (真实命令tsc -b && vite build),生产dist包。
拷贝本地生产 dist包 到D:demo文件夹下改名为 前端包对应的名称例如:demo-app.
新建 nginx.conf文件
配置如下
worker_processes 1;events { worker_connections 1024;}http { include ...mime.types;//nginx程序目录下的mime.types文件导入(win下用绝对路径) default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 443 ssl;server_name localhost; //自签名文件对应的配置(win下配置绝对路径)ssl_certificate ../cert/server.crt;ssl_certificate_key ../cert/server.key;# 前端服务location / {root ./demo/demo-app; // win下配置绝对路径try_files $uri $uri/ /index.html;index index.html;autoindex off; server_tokens on;add_header X-Content-Type-Options \"nosniff\";add_header Content-Type \"text/html; charset=utf-8\";# 允许所有来源访问add_header \'Access-Control-Allow-Origin\' \'*\';# 允许的请求方法add_header \'Access-Control-Allow-Methods\' \'GET, POST, OPTIONS, PUT, DELETE\';# 允许的请求头add_header \'Access-Control-Allow-Headers\' \'Content-Type, Authorization, X-Requested-With\';# 允许带凭证的跨域请求add_header \'Access-Control-Allow-Credentials\' \'true\';# 预检请求处理if ($request_method = \'OPTIONS\') {add_header \'Access-Control-Max-Age\' 1728000;add_header \'Content-Type\' \'text/plain; charset=utf-8\';add_header \'Content-Length\' 0;return 204;}}# API代理location /api/ {proxy_pass https://localhost:[端口号]/api/;proxy_ssl_verify off; proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection \'upgrade\';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_cache_bypass $http_upgrade;# 跨域传递add_header \'Access-Control-Allow-Origin\' \'$http_origin\';add_header \'Access-Control-Allow-Credentials\' \'true\';add_header \'Access-Control-Allow-Methods\' \'GET, POST, PUT, DELETE, OPTIONS\';} # 静态文件代理location /static/ { proxy_pass https://localhost:[端口号]/static/;proxy_ssl_verify off; proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection \'upgrade\';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_cache_bypass $http_upgrade;# 跨域传递add_header \'Access-Control-Allow-Origin\' \'$http_origin\';add_header \'Access-Control-Allow-Credentials\' \'true\';add_header \'Access-Control-Allow-Methods\' \'GET, POST, PUT, DELETE, OPTIONS\';}}}
具体配置结合业务需求修改。
这块就把 Express API 代理 和 前端的页面配到了一个服务。
之后就cd 到 nginx 程序目录下 cmd nginx -c ../nginx.conf (win用绝对路径)
没有报错,在 浏览器中使用 https://localhost 测试 nginx 服务是否发布成功。
成功会跳转到发布的本地测试服务 首页
也可以用https://[局域网本机IP] 访问测试服务。(局域网内测试使用)
扩展:如果追求安全性可以使用 Docker容器中的 nginx镜像 发布应用。