Files
novalon-website/nginx-static-production.conf
T
张翔 10404dbb36 chore: sync marketing pages, CMS extensions, tests and project docs
同步工作区剩余变更,主要包括:
- 营销页面组件与布局持续优化(about/news/services/solutions/team 等)
- 详情页四层叙事组件、布局组件、UI 组件调整
- CMS 数据模型、API 路由、权限、工作流、站内通知、媒体管理扩展
- 新增/补充单元测试与 E2E 测试(cms-workflow.spec.ts 等)
- ESLint 9 迁移、jest/tsconfig 配置更新、依赖调整
- 新增 ADR、CMS 评估文档、Release Review / Acceptance 报告
- 移除水墨装饰组件与大体积未使用字体文件
2026-07-25 08:04:01 +08:00

219 lines
7.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Novalon 生产环境 Nginx 配置(混合渲染)
#
# 架构:
# - 静态资源(/_next/static、/fonts、/uploads、图片)由 Nginx 直接服务并长期缓存。
# - /api/*、/admin/* 代理到 Next.js 运行时(SSR/API Routes)。
# - 页面请求优先命中 /var/www/novalon 中的预构建静态 HTML;未命中时回源到
# Next.js 运行时,用于 ISR 首次渲染、Draft Mode 预览及动态路由。
#
# 前置条件:
# - nextjs_app upstream 指向运行 `next start` 的 Next.js 服务。
# - 默认使用 docker-compose.server.yml 中的服务名 novalon-website:3000。
# - 验证:nginx -t && nginx -s reload
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
resolver 127.0.0.11 valid=30s ipv6=off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
server_tokens off;
client_max_body_size 100M;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
limit_req_zone $binary_remote_addr zone=general:10m rate=100r/s;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+text text/javascript;
upstream gitea_app {
server gitea:3000;
}
upstream jenkins_app {
server jenkins:8080;
}
# Next.js 混合渲染服务(SSR/ISR/API Routes
# 必须与 docker-compose.server.yml 中 Next.js 服务名/端口一致
upstream nextjs_app {
server novalon-website:3000;
}
# WebSocket 连接升级映射(Next.js HMR / 实时功能使用)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# 反向代理通用头(用于 /api/*、/admin/* 及 ISR 回源)
proxy_http_version 1.1;
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_set_header X-Forwarded-Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Novalon 主站 - 静态文件 + SSR/ISR 回源
server {
listen 80;
server_name novalon.cn www.novalon.cn;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://www.novalon.cn$request_uri;
}
}
server {
listen 443 ssl;
http2 on;
server_name novalon.cn www.novalon.cn;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
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;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 静态文件根目录
root /var/www/novalon;
index index.html;
# 静态资源长期缓存
location /_next/static/ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
try_files $uri =404;
}
# 字体文件缓存
location ~* \.(ttf|woff|woff2|eot)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Access-Control-Allow-Origin "*";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
try_files $uri =404;
}
# 图片文件缓存
location ~* \.(svg|jpg|jpeg|png|gif|webp|avif|ico)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
try_files $uri =404;
}
# 上传媒体文件(本地存储时落盘到 public/uploads/
location /uploads/ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
try_files $uri =404;
}
# Let's Encrypt ACME challenge
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# CMS / 联系表单 / 认证等 API 路由:禁止缓存,代理到 Next.js
location /api/ {
limit_req zone=general burst=50 nodelay;
proxy_pass http://nextjs_app;
proxy_hide_header X-Powered-By;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
# 管理后台与 Draft Mode:代理到 Next.jsCookie 透传以支持 draft 预览
location /admin/ {
limit_req zone=general burst=20 nodelay;
proxy_pass http://nextjs_app;
proxy_hide_header X-Powered-By;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
# Next.js 静态导出的页面路由 + ISR/SSR 回源
# 1) 优先命中已构建的静态 HTML/资源
# 2) 未命中时转交给 Next.js 运行时(ISR 首次渲染、Draft 预览、动态路由)
location / {
limit_req zone=general burst=20 nodelay;
try_files $uri $uri.html $uri/ @nextjs;
}
# ISR/SSR 回源 named location
location @nextjs {
proxy_pass http://nextjs_app;
proxy_hide_header X-Powered-By;
}
# 自定义 404 页面(Nginx 层面未命中且 Next.js 也返回 404 时展示)
error_page 404 /404.html;
# 优化文件传输
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
include /etc/nginx/conf.d/*.conf;
}