Nginx 完整配置参考
生成日期:2026-09-16
用途:客户现场入口 Nginx。location 按产品统一模板locations-ruoyi-office.inc裁剪:根路径进管理端,不含文档站 / CI / 天气网关 / 体验包。Windows 路径见 Windows 部署。
各手册里的「最小配置」只保证能打开 /web 并登录。下面是与演示站同一套路径约定的完整 server 块。
落地前必改
server_name改成现场域名或入口 IP。- 所有
proxy_pass里的127.0.0.1:48080:宿主机 Nginx 保持本机;Compose 内改yudao-server:48080;微服务改gateway-server:48080。不要剥掉/admin-api、/app-api前缀。 - 模板里静态目录是容器路径
/usr/share/nginx/html/...。宿主机 Nginx 改成/data/nginx/html/...;宝塔常见/www/wwwroot/ruoyi-office/web/。 - 未部署的能力整段删除(
/mall、/goview、积木、OnlyOffice、LiveKit)。 - 积木必须同时保留
/web/jmreport+/jmreport、/web/drag+/drag。生产包VITE_BASE_URL=/web,iframe 第一跳是/web/jmreport/list;设计器内部资源走根路径/jmreport/。只留其中一对,iframe 会变成管理端首页或 JS 404。 - 改完
nginx -t && nginx -s reload。已有default.conf同时听 80 时先关掉。
$connection_upgrade 必须写在 http { } 里(与 server 平级),OnlyOffice / LiveKit 的 WebSocket 要用。积木 / WebSocket location 必须与 location /web 平级,不要嵌进 /web { }。
路径一览
| 浏览器路径 | 作用 | 是否必配 |
|---|---|---|
/ | 302 到 /web/ | 必配 |
/web | PC 管理端静态(Vben) | 必配 |
/admin-api | 管理端 API | 必配 |
/infra/ws、/web/infra/ws | 实时消息 WebSocket | 必配 |
/app、/app-api | UniApp H5 + 移动端 API | 有移动端时必配 |
/mall | 商城 H5(history 路由,接口走 /app-api) | 合同含商城时 |
/goview | GoView 大屏 | 合同含大屏时 |
/web/jmreport、/web/drag 与 /jmreport、/drag | 积木报表 / 仪表盘(两套前缀都要) | 用报表时 |
/onlyoffice/、/cache/、/coauthoring/ | OnlyOffice | 合同含在线编辑时 |
/livekit/ | IM 音视频信令 | 启用通话时 |
/health | Nginx 探活 | 建议 |
OnlyOffice 同 Compose 网络用服务名 onlyoffice-documentserver。LiveKit 媒体口 7881/7882(TCP/UDP)不走 Nginx,需对客户端放行。
http 级(与 server 平级)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}完整配置(HTTP)
放到 /data/nginx/conf/conf.d/ruoyi-office.conf(或宝塔 vhost/nginx/)。80 / 443 可把下面 server 内 location 抽成 .inc,两边 include,与演示站 ruoyi-office.conf 同一做法。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _; # 改成现场域名或入口 IP
charset utf-8;
# 合同模板、附件经 /admin-api/infra/file/upload 走后端;默认 1m 会被 Nginx 直接断开
client_max_body_size 100m;
access_log /var/log/nginx/ruoyi-office-access.log;
error_log /var/log/nginx/ruoyi-office-error.log;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/x-javascript image/svg+xml;
gzip_static on;
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Let's Encrypt HTTP-01(certbot webroot 时保留)
location ^~ /.well-known/acme-challenge/ {
root /usr/share/nginx/html/acme;
default_type text/plain;
}
location = / {
return 302 /web/;
}
# 企业云盘独立编辑页:旧入口 window.open("/oa/cloud/file-editor?...") 会打到站点根。
# 生产为 hash 路由 + /web 子路径。Location 中 # 必须用引号。
location = /oa/cloud/file-editor {
return 302 "/web/#/oa/cloud/file-editor$is_args$args";
}
# ========================================
# Vben Admin(/web 子路径)
# ========================================
location /web {
alias /usr/share/nginx/html/web;
index index.html;
# 使用 alias 时,try_files 的路径相对 alias 目录
try_files $uri $uri/ /web/index.html;
}
location ~* ^/web/(.+)\.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot|map)$ {
root /usr/share/nginx/html;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ ^/web/\. {
deny all;
access_log off;
log_not_found off;
}
# ========================================
# WebSocket
# ========================================
# 后端实际路径为 /infra/ws。
# /web/infra/ws 兼容旧版前端错误拼接,避免被 /web 静态站拦截。
location ^~ /infra/ws {
proxy_pass http://127.0.0.1:48080/infra/ws;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
location ^~ /web/infra/ws {
proxy_pass http://127.0.0.1:48080/infra/ws;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
# ========================================
# UniApp H5(/app)
# ========================================
location /app {
alias /usr/share/nginx/html/app;
index index.html;
try_files $uri $uri/ /app/index.html;
}
location ~* ^/app/(.+)\.(jpg|jpeg|png|gif|ico|css|js|mjs|svg|woff|woff2|ttf|eot|map|json|mp3|mp4|webm|ogg|wav|flac|aac)$ {
root /usr/share/nginx/html;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ ^/app/\. {
deny all;
access_log off;
log_not_found off;
}
# ========================================
# 商城 H5(/mall,未部署可整段删除)
# ========================================
# 商城为 history 路由;接口前缀 /app-api(见下方)。
location /mall {
alias /usr/share/nginx/html/mall;
index index.html;
try_files $uri $uri/ /mall/index.html;
}
location ~* ^/mall/(.+)\.(jpg|jpeg|png|gif|ico|css|js|mjs|svg|woff|woff2|ttf|eot|map|json|mp3|mp4|webm|ogg|wav|flac|aac)$ {
root /usr/share/nginx/html;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ ^/mall/\. {
deny all;
access_log off;
log_not_found off;
}
# ========================================
# GoView(/goview,未部署可整段删除)
# ========================================
location /goview {
alias /usr/share/nginx/html/goview;
index index.html;
try_files $uri $uri/ /goview/index.html;
}
location ~* ^/goview/(.+)\.(jpg|jpeg|png|gif|ico|css|js|mjs|svg|woff|woff2|ttf|eot|map|json|mp3|mp4|webm|ogg|wav|flac|aac)$ {
root /usr/share/nginx/html;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ ^/goview/\. {
deny all;
access_log off;
log_not_found off;
}
# ========================================
# 积木报表(后端 iframe)
# ========================================
# 必须同时代理 /web/jmreport(当前前端 VITE_BASE_URL=/web)和 /jmreport(设计器内部资源)。
# 缺 /web/jmreport 时,/web 的 try_files 把 /web/jmreport/list 回成 index.html,iframe 里是管理端首页。
location /web/jmreport {
proxy_pass http://127.0.0.1:48080/jmreport;
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;
}
location /web/drag {
proxy_pass http://127.0.0.1:48080/drag;
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;
}
location /jmreport {
proxy_pass http://127.0.0.1:48080/jmreport;
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;
}
location /drag {
proxy_pass http://127.0.0.1:48080/drag;
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;
}
# ========================================
# OnlyOffice(未采购可整段删除)
# ========================================
# Compose 同网络把 127.0.0.1:8081 换成 onlyoffice-documentserver。
# X-Forwarded-Host 必须带 /onlyoffice 后缀,否则 DS 下发根路径 /cache,被 SPA 接走。
# Connection 走 map:非 WebSocket 不能写死 upgrade。
location /onlyoffice/ {
proxy_pass http://127.0.0.1:8081/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_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_set_header X-Forwarded-Host $http_host/onlyoffice;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
client_max_body_size 100m;
proxy_buffering off;
}
location /cache/ {
proxy_pass http://127.0.0.1:8081/cache/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_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_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
client_max_body_size 100m;
proxy_buffering off;
}
location /coauthoring/ {
proxy_pass http://127.0.0.1:8081/coauthoring/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_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_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffering off;
}
# ========================================
# LiveKit 信令(未启用可整段删除)
# ========================================
# 浏览器 / App:wss://<入口>/livekit ;媒体 UDP/TCP 不走 Nginx
location ^~ /livekit/ {
proxy_pass http://127.0.0.1:7880/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
location = /livekit {
return 301 /livekit/;
}
# ========================================
# 后端 API(不要剥掉前缀)
# ========================================
location /admin-api {
proxy_pass http://127.0.0.1:48080/admin-api;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
client_max_body_size 100m;
proxy_request_buffering off;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
}
location /app-api {
proxy_pass http://127.0.0.1:48080/app-api;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
client_max_body_size 100m;
proxy_request_buffering off;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
}
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}sudo nginx -t && sudo nginx -s reload
# Docker 内的 Nginx:
# sudo docker exec nginx nginx -t && sudo docker exec nginx nginx -s reload宝塔若在「伪静态」里又写了 try_files ... /index.html,会把 /web/jmreport 打回首页。伪静态不要覆盖积木这两个前缀。
HTTPS
证书放到约定目录后,再加一个 listen 443 ssl 的 server,location 与上面完全相同。推荐抽 .inc 后 80 / 443 各 include 一次。
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name oa.example.com;
ssl_certificate /data/nginx/ssl/oa.example.com/fullchain.pem;
ssl_certificate_key /data/nginx/ssl/oa.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
include /etc/nginx/conf.d/locations-ruoyi-office.inc;
}Nginx 1.25.1+ 也可写成 listen 443 ssl; + http2 on;。
切 HTTPS 后同步改:文件配置「自定义域名」、OnlyOffice server-url、UniApp 绝对 URL、LiveKit livekit-url(wss://<入口>/livekit)。见 域名、存储与 OnlyOffice。
形态差异
| 形态 | proxy_pass 上游 | 静态目录 |
|---|---|---|
| 宿主机 Nginx + JAR | http://127.0.0.1:48080 | /data/nginx/html/... |
| Compose 内 Nginx | http://yudao-server:48080 | 容器 /usr/share/nginx/html/... |
| 微服务 | http://gateway-server:48080 | 同上;不要剥掉 /admin-api |
| 宝塔 | http://127.0.0.1:48080 | /www/wwwroot/ruoyi-office/web/ 等 |
| Windows | http://127.0.0.1:48080 | C:/ruoyi-office/app/web/,见 Windows 部署 |
OnlyOffice 与后端必须在同一入口域名下;X-Forwarded-Host 带 /onlyoffice 后缀,并反代 /cache/、/coauthoring/。排障见 域名、存储与 OnlyOffice。
LiveKit:yudao.im.rtc.livekit-url 填 wss://<入口>/livekit;livekit-api-url 填服务端直连(如 http://127.0.0.1:7880)。
验证
| 检查项 | 命令 / 地址 | 预期 |
|---|---|---|
| 语法 | nginx -t | syntax is ok |
| 根路径 | 浏览器打开 http://<入口>/ | 跳到 /web/ 登录页 |
| API | 登录,网络面板 /admin-api 无 502 | 进入首页 |
| 上传 | 管理端传 >1MB 附件 | 成功;失败先看 client_max_body_size |
| WebSocket | 登录后消息/待办能实时刷新 | 无一直 404 的 /infra/ws |
| 积木报表(若有) | curl -sI http://<入口>/web/jmreport/list | 不是管理端 index.html;nginx -T 同时有 /web/jmreport 和 /jmreport |
| OnlyOffice(若有) | 打开一份 docx | 不报 Editor.bin / 扩展名不匹配 |
| LiveKit(若有) | curl -sI http://<入口>/livekit/ | 200;通话能进房 |
首次登录验收仍按对应部署手册勾选,然后进入 上线文档。
