nsbp-cli 0.2.23 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/bin/nsbp.js +6 -9
  3. package/package.json +1 -1
  4. package/templates/basic/.env.development +13 -0
  5. package/templates/basic/.env.example +33 -0
  6. package/templates/basic/.env.production +17 -0
  7. package/templates/basic/Makefile +60 -18
  8. package/templates/basic/README.md +152 -0
  9. package/templates/basic/{webpack.base.js → config/webpack.base.js} +2 -2
  10. package/templates/basic/{webpack.client.js → config/webpack.client.js} +2 -2
  11. package/templates/basic/{webpack.server.js → config/webpack.server.js} +3 -3
  12. package/templates/basic/{Dockerfile → docker/Dockerfile} +1 -1
  13. package/templates/basic/{docker-compose.dev.yml → docker/docker-compose.dev.yml} +12 -7
  14. package/templates/basic/{docker-compose.yml → docker/docker-compose.yml} +8 -4
  15. package/templates/basic/docs/ENV_CONFIG_GUIDE.md +346 -0
  16. package/templates/basic/docs/QUICKSTART.md +99 -0
  17. package/templates/basic/gitignore +2 -0
  18. package/templates/basic/package.json +8 -6
  19. package/templates/basic/public/apple-touch-icon.png +0 -0
  20. package/templates/basic/public/favicon-16x16.png +0 -0
  21. package/templates/basic/public/favicon-192x192.png +0 -0
  22. package/templates/basic/public/favicon-32x32.png +0 -0
  23. package/templates/basic/public/favicon-512x512.png +0 -0
  24. package/templates/basic/public/favicon.svg +10 -0
  25. package/templates/basic/public/site.webmanifest +20 -0
  26. package/templates/basic/scripts/verify-dev.sh +6 -6
  27. package/templates/basic/scripts/verify-security.sh +124 -0
  28. package/templates/basic/src/server/index.ts +56 -2
  29. package/templates/basic/src/server/utils.tsx +7 -0
  30. /package/templates/basic/{postcss.config.js → config/postcss.config.js} +0 -0
  31. /package/templates/basic/{.dockerignore → docker/.dockerignore} +0 -0
  32. /package/templates/basic/{Dockerfile.dev → docker/Dockerfile.dev} +0 -0
package/README.md CHANGED
@@ -147,7 +147,7 @@ node ./bin/nsbp.js --help # Test CLI locally
147
147
 
148
148
  - **Package Name**: `nsbp-cli`
149
149
  - **Bin Command**: `nsbp` (install globally and run `nsbp --help`)
150
- - **Version**: `0.2.23`
150
+ - **Version**: `0.2.25`
151
151
  - **Dependencies**: chalk, commander, fs-extra, inquirer
152
152
  - **Package Manager**: Uses pnpm (also compatible with npm)
153
153
  - **Node Version**: >=16.0.0
package/bin/nsbp.js CHANGED
@@ -55,19 +55,16 @@ program
55
55
  'src',
56
56
  'public',
57
57
  'scripts',
58
- 'webpack.base.js',
59
- 'webpack.client.js',
60
- 'webpack.server.js',
58
+ 'config',
59
+ 'docker',
60
+ 'docs',
61
+ '.env.example',
62
+ '.env.development',
63
+ '.env.production',
61
64
  'tsconfig.json',
62
- 'postcss.config.js',
63
65
  '.prettierrc',
64
66
  '.prettierignore',
65
67
  'gitignore',
66
- '.dockerignore',
67
- 'docker-compose.yml',
68
- 'docker-compose.dev.yml',
69
- 'Dockerfile',
70
- 'Dockerfile.dev',
71
68
  'Makefile',
72
69
  'README.md'
73
70
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nsbp-cli",
3
- "version": "0.2.23",
3
+ "version": "0.2.25",
4
4
  "description": "CLI tool for creating NSBP (Node React SSR by Webpack) projects",
5
5
  "main": "index.js",
6
6
  "homepage": "https://nsbp.erishen.cn/",
@@ -0,0 +1,13 @@
1
+ # NSBP 开发环境配置
2
+
3
+ # ==================== 运行环境配置 ====================
4
+ NODE_ENV=development
5
+ PORT=3001
6
+
7
+ # ==================== 安全配置 ====================
8
+ # 开发环境禁用速率限制(影响开发效率)
9
+ ENABLE_RATE_LIMIT=0
10
+
11
+ # ==================== 调试配置 ====================
12
+ # 启用详细日志便于调试
13
+ # DEBUG=nsbp:*
@@ -0,0 +1,33 @@
1
+ # NSBP 环境变量配置
2
+ # 复制此文件为 .env 并根据需要修改配置
3
+
4
+ # ==================== 运行环境配置 ====================
5
+ NODE_ENV=development
6
+ PORT=3001
7
+
8
+ # ==================== 安全配置 ====================
9
+ # 启用速率限制(1=启用,0=禁用)
10
+ # 开发环境建议禁用,生产环境建议启用
11
+ ENABLE_RATE_LIMIT=0
12
+
13
+ # ==================== Docker 配置(Docker 部署时使用)====================
14
+ # Docker 镜像标签(可选)
15
+ # DOCKER_IMAGE_TAG=latest
16
+
17
+ # ==================== 调试配置 ====================
18
+ # 启用详细日志(开发时有用)
19
+ # DEBUG=nsbp:*
20
+
21
+ # ==================== 性能配置 ====================
22
+ # 启用性能监控(生产环境可选)
23
+ # ENABLE_PERFORMANCE_MONITORING=0
24
+
25
+ # ==================== 其他配置 ====================
26
+ # 时区(可选)
27
+ # TZ=Asia/Shanghai
28
+
29
+ # ==================== 注意事项 ====================
30
+ # 1. 不要将 .env 文件提交到 Git(已在 .gitignore 中忽略)
31
+ # 2. 敏感信息(密钥、密码)请放在 .env.local 中
32
+ # 3. .env.local 不会被提交到 Git,适合存放敏感信息
33
+ # 4. 优先级:.env.local > .env > 默认值
@@ -0,0 +1,17 @@
1
+ # NSBP 生产环境配置
2
+
3
+ # ==================== 运行环境配置 ====================
4
+ NODE_ENV=production
5
+ PORT=3001
6
+
7
+ # ==================== 安全配置 ====================
8
+ # 生产环境启用速率限制(防止 DDoS 和暴力攻击)
9
+ ENABLE_RATE_LIMIT=1
10
+
11
+ # ==================== 性能配置 ====================
12
+ # 生产环境关闭调试日志
13
+ # DEBUG=
14
+
15
+ # ==================== 其他配置 ====================
16
+ # 时区
17
+ TZ=Asia/Shanghai
@@ -1,4 +1,4 @@
1
- .PHONY: help build dev prod down clean logs restart
1
+ .PHONY: help build dev prod down clean logs restart env-dev env-prod env-local
2
2
 
3
3
  # Package manager detection
4
4
  PNPM := $(shell which pnpm)
@@ -19,48 +19,90 @@ help: ## Show this help message
19
19
  @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
20
20
 
21
21
  build: ## Build Docker images for production
22
- $(COMPOSE) build
22
+ $(COMPOSE) -f docker/docker-compose.yml build
23
23
 
24
24
  build-dev: ## Build Docker images for development
25
- $(COMPOSE) -f docker-compose.dev.yml build
25
+ $(COMPOSE) -f docker/docker-compose.dev.yml build
26
26
 
27
27
  dev: ## Start development environment (removes orphan containers)
28
- $(COMPOSE) -f docker-compose.dev.yml up --build --remove-orphans
28
+ $(COMPOSE) -f docker/docker-compose.dev.yml up --build --remove-orphans
29
29
 
30
30
  prod: ## Start production environment (removes orphan containers)
31
- $(COMPOSE) up -d --remove-orphans
31
+ $(COMPOSE) -f docker/docker-compose.yml up -d --remove-orphans
32
32
 
33
33
  down: ## Stop and remove containers (including orphan containers)
34
- $(COMPOSE) down --remove-orphans
35
- $(COMPOSE) -f docker-compose.dev.yml down --remove-orphans
34
+ $(COMPOSE) -f docker/docker-compose.yml down --remove-orphans
35
+ $(COMPOSE) -f docker/docker-compose.dev.yml down --remove-orphans
36
36
 
37
37
  clean: ## Stop containers, remove images and volumes (including orphan containers)
38
- $(COMPOSE) down -v --rmi all --remove-orphans
39
- $(COMPOSE) -f docker-compose.dev.yml down -v --rmi all --remove-orphans
38
+ $(COMPOSE) -f docker/docker-compose.yml down -v --rmi all --remove-orphans
39
+ $(COMPOSE) -f docker/docker-compose.dev.yml down -v --rmi all --remove-orphans
40
40
 
41
41
  logs: ## View logs
42
- $(COMPOSE) logs -f
42
+ $(COMPOSE) -f docker/docker-compose.yml logs -f
43
43
 
44
44
  logs-dev: ## View development logs
45
- $(COMPOSE) -f docker-compose.dev.yml logs -f
45
+ $(COMPOSE) -f docker/docker-compose.dev.yml logs -f
46
46
 
47
47
  restart: ## Restart production containers
48
- $(COMPOSE) restart
48
+ $(COMPOSE) -f docker/docker-compose.yml restart
49
49
 
50
50
  restart-dev: ## Restart development containers
51
- $(COMPOSE) -f docker-compose.dev.yml restart
51
+ $(COMPOSE) -f docker/docker-compose.dev.yml restart
52
52
 
53
53
  rebuild: ## Rebuild and restart production containers (removes orphan containers)
54
- $(COMPOSE) up -d --build --remove-orphans
54
+ $(COMPOSE) -f docker/docker-compose.yml up -d --build --remove-orphans
55
55
 
56
56
  rebuild-dev: ## Rebuild and restart development containers (removes orphan containers)
57
- $(COMPOSE) -f docker-compose.dev.yml up -d --build --remove-orphans
57
+ $(COMPOSE) -f docker/docker-compose.dev.yml up -d --build --remove-orphans
58
58
 
59
59
  shell: ## Open shell in production container
60
- $(COMPOSE) exec app sh
60
+ $(COMPOSE) -f docker/docker-compose.yml exec app sh
61
61
 
62
62
  shell-dev: ## Open shell in development container
63
- $(COMPOSE) -f docker-compose.dev.yml exec app sh
63
+ $(COMPOSE) -f docker/docker-compose.dev.yml exec app sh
64
64
 
65
65
  test: ## Run tests (if configured)
66
- $(COMPOSE) exec app $(PM) test
66
+ $(COMPOSE) -f docker/docker-compose.yml exec app $(PM) test
67
+
68
+ env-dev: ## Set up development environment
69
+ @if [ -f .env.development ]; then \
70
+ cp .env.development .env && \
71
+ echo -e "\033[0;32m✅ 开发环境已配置 (.env)\033[0m"; \
72
+ else \
73
+ echo -e "\033[0;33m⚠️ .env.development 不存在\033[0m"; \
74
+ fi
75
+
76
+ env-prod: ## Set up production environment
77
+ @if [ -f .env.production ]; then \
78
+ cp .env.production .env && \
79
+ echo -e "\033[0;32m✅ 生产环境已配置 (.env)\033[0m"; \
80
+ else \
81
+ echo -e "\033[0;33m⚠️ .env.production 不存在\033[0m"; \
82
+ fi
83
+
84
+ env-local: ## Set up local environment with sensitive data
85
+ @if [ ! -f .env.local ]; then \
86
+ echo "# Local environment (contains sensitive data)" > .env.local && \
87
+ echo "# DO NOT commit this file to Git" >> .env.local && \
88
+ echo -e "\033[0;32m✅ .env.local 已创建\033[0m"; \
89
+ echo "请编辑 .env.local 添加敏感信息"; \
90
+ else \
91
+ echo -e "\033[0;33m⚠️ .env.local 已存在\033[0m"; \
92
+ fi
93
+
94
+ show-env: ## Show current environment variables
95
+ @echo "========================================="
96
+ @echo "当前环境变量配置"
97
+ @echo "========================================="
98
+ @echo ""
99
+ @if [ -f .env ]; then \
100
+ echo "📄 .env 文件内容:"; \
101
+ cat .env | grep -v "^#" | grep -v "^$$"; \
102
+ else \
103
+ echo "⚠️ .env 文件不存在"; \
104
+ fi
105
+ @echo ""
106
+ @if [ -f .env.local ]; then \
107
+ echo "📄 .env.local 文件存在(包含敏感信息)"; \
108
+ fi
@@ -2,6 +2,84 @@
2
2
 
3
3
  🌐 **Online Demo**: [https://nsbp.erishen.cn/](https://nsbp.erishen.cn/)
4
4
 
5
+ ## 环境变量配置
6
+
7
+ ### 快速开始
8
+
9
+ ```bash
10
+ # 1. 复制环境变量模板
11
+ cp .env.example .env
12
+
13
+ # 2. 根据需要编辑 .env 文件
14
+ # 编辑 NODE_ENV、PORT、ENABLE_RATE_LIMIT 等
15
+
16
+ # 3. 开始开发或部署
17
+ pnpm run dev # 本地开发
18
+ docker-compose up -d # Docker 部署
19
+ ```
20
+
21
+ ### 环境变量说明
22
+
23
+ | 变量名 | 默认值 | 说明 | 推荐环境 |
24
+ |-------|--------|------|---------|
25
+ | `NODE_ENV` | development | 运行环境 (development/production) | 全部 |
26
+ | `PORT` | 3001 | 服务端口 | 全部 |
27
+ | `ENABLE_RATE_LIMIT` | 0 | 启用速率限制 (1=启用, 0=禁用) | 生产环境 |
28
+ | `DEBUG` | - | 启用调试日志 | 开发环境 |
29
+ | `TZ` | Asia/Shanghai | 时区配置 | 生产环境 |
30
+
31
+ ### 配置文件说明
32
+
33
+ - **`.env.example`** - 环境变量模板(提交到 Git)
34
+ - **`.env`** - 本地开发配置(不提交到 Git)
35
+ - **`.env.production`** - 生产环境配置(不提交到 Git)
36
+ - **`.env.development`** - 开发环境配置(不提交到 Git)
37
+ - **`.env.local`** - 本地敏感信息(最高优先级,不提交到 Git)
38
+
39
+ ### 配置优先级
40
+
41
+ ```
42
+ .env.local > .env > docker-compose.yml 默认值
43
+ ```
44
+
45
+ ### 本地开发配置
46
+
47
+ ```bash
48
+ # 复制开发环境配置
49
+ cp .env.development .env
50
+
51
+ # 或手动创建 .env 文件
52
+ cat > .env << EOF
53
+ NODE_ENV=development
54
+ PORT=3001
55
+ ENABLE_RATE_LIMIT=0
56
+ EOF
57
+
58
+ # 启动开发环境
59
+ pnpm run dev
60
+ ```
61
+
62
+ ### Docker 部署配置
63
+
64
+ ```bash
65
+ # 生产环境配置
66
+ cp .env.production .env
67
+
68
+ # Docker Compose 会自动读取 .env 文件
69
+ docker-compose up -d
70
+
71
+ # 查看环境变量是否生效
72
+ docker-compose exec app env | grep NODE_ENV
73
+ ```
74
+
75
+ ### 敏感信息管理
76
+
77
+ **重要:**
78
+ - ✅ `.env.example` 可以提交到 Git(模板文件)
79
+ - ❌ `.env`、`.env.local` 不要提交到 Git(已在 .gitignore 中)
80
+ - ✅ 敏感信息(密钥、数据库密码)放在 `.env.local` 中
81
+ - ✅ `.env.local` 会覆盖其他配置,优先级最高
82
+
5
83
  ## 开发
6
84
  - pnpm run dev (开发运行)
7
85
  - pnpm run build (生产编译)
@@ -141,6 +219,80 @@ make rebuild-dev # 重新构建并启动开发环境
141
219
 
142
220
  - `NODE_ENV`: 运行环境 (production/development)
143
221
  - `PORT`: 服务端口 (默认 3001)
222
+ - `ENABLE_RATE_LIMIT`: 启用速率限制 (1=启用,0=禁用,默认禁用)
223
+
224
+ ## 安全特性
225
+
226
+ NSBP 内置了多层安全防护,默认启用生产级安全配置:
227
+
228
+ ### 已启用的安全措施
229
+
230
+ #### 1. **HTTP 头部安全 (Helmet)**
231
+ - Content Security Policy (CSP): 防止 XSS 攻击
232
+ - X-Frame-Options: 防止点击劫持
233
+ - X-Content-Type-Options: 防止 MIME 类型嗅探
234
+ - Strict-Transport-Security: 强制 HTTPS
235
+ - X-XSS-Protection: XSS 保护
236
+ - Referrer-Policy: 控制引用信息
237
+
238
+ #### 2. **静态文件安全**
239
+ - ✅ 禁止访问 `.env`、`.git` 等敏感文件
240
+ - ✅ 静态资源缓存优化(1 年缓存)
241
+ - ✅ 请求体大小限制(10MB)
242
+
243
+ #### 3. **技术栈隐藏**
244
+ - ✅ 移除 `X-Powered-By` 头部
245
+ - ✅ 不暴露 Express 版本信息
246
+
247
+ #### 4. **速率限制 (可选)**
248
+ - ✅ 15 分钟内最多 100 次请求
249
+ - ✅ 自动限流恶意 IP
250
+ - ✅ 可通过环境变量启用/禁用
251
+
252
+ ### 启用速率限制
253
+
254
+ 在生产环境中,建议启用速率限制以防止 DDoS 攻击:
255
+
256
+ **Docker 方式:**
257
+ ```bash
258
+ # docker-compose.yml 中添加
259
+ environment:
260
+ - ENABLE_RATE_LIMIT=1
261
+ ```
262
+
263
+ **本地开发方式:**
264
+ ```bash
265
+ # .env 文件
266
+ ENABLE_RATE_LIMIT=1
267
+
268
+ # 或命令行
269
+ ENABLE_RATE_LIMIT=1 pnpm start
270
+ ```
271
+
272
+ ### 安全最佳实践
273
+
274
+ #### 生产环境建议
275
+ 1. ✅ **启用 HTTPS**: 使用反向代理(Nginx/Apache)配置 SSL
276
+ 2. ✅ **启用速率限制**: 防止暴力攻击和 DDoS
277
+ 3. ✅ **设置强密码**: 数据库、API 密钥等
278
+ 4. ✅ **定期更新依赖**: `pnpm update`
279
+ 5. ✅ **配置防火墙**: 限制入站流量
280
+
281
+ #### 开发环境
282
+ - ✅ 默认配置已足够
283
+ - ❌ 不建议启用速率限制(影响开发效率)
284
+ - ✅ 保留详细错误日志便于调试
285
+
286
+ ### 安全检查清单
287
+
288
+ 部署前请确认:
289
+ - [ ] 已安装最新依赖 (`pnpm install`)
290
+ - [ ] 环境变量已配置(NODE_ENV=production)
291
+ - [ ] HTTPS 已配置
292
+ - [ ] 敏感信息(密钥、数据库密码)已移出代码库
293
+ - [ ] 速率限制已启用(生产环境)
294
+ - [ ] 静态文件访问已测试
295
+ - [ ] CSP 策略已测试(检查控制台错误)
144
296
 
145
297
  ### CLI 发布
146
298
 
@@ -2,7 +2,7 @@ const path = require('path')
2
2
  const MiniCssExtractPlugin = require('mini-css-extract-plugin')
3
3
  const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
4
4
  const TerserPlugin = require('terser-webpack-plugin')
5
- const { version } = require('./package.json')
5
+ const { version } = require('../package.json')
6
6
  const LoadablePlugin = require('@loadable/webpack-plugin')
7
7
  const { createLoadableComponentsTransformer } = require('typescript-loadable-components-plugin')
8
8
  const BrowserSyncPlugin = require('browser-sync-webpack-plugin')
@@ -54,7 +54,7 @@ module.exports = ({ mode, entry, server, init }) => {
54
54
  logInfoToStdOut: true,
55
55
  logLevel: 'info',
56
56
  transpileOnly: true,
57
- configFile: path.resolve(__dirname, './tsconfig.json'),
57
+ configFile: path.resolve(__dirname, '../tsconfig.json'),
58
58
  getCustomTransformers: (program) => {
59
59
  // console.log('getCustomTransformers', program)
60
60
 
@@ -1,7 +1,7 @@
1
1
  const path = require('path') //node的path模块
2
2
  const { merge } = require('webpack-merge')
3
3
  const config = require('./webpack.base.js')
4
- const { version } = require('./package.json')
4
+ const { version } = require('../package.json')
5
5
 
6
6
  const server = false
7
7
 
@@ -12,7 +12,7 @@ const entry = {
12
12
  const clientConfig = {
13
13
  output: {
14
14
  //打包出口
15
- path: path.resolve(__dirname, 'public'),
15
+ path: path.resolve(__dirname, '../public'),
16
16
  filename: ({ chunk }) => {
17
17
  const { name } = chunk
18
18
  // console.log('name', name)
@@ -2,7 +2,7 @@ const path = require('path') //node的path模块
2
2
  const nodeExternals = require('webpack-node-externals')
3
3
  const { merge } = require('webpack-merge')
4
4
  const config = require('./webpack.base.js')
5
- const { version } = require('./package.json')
5
+ const { version } = require('../package.json')
6
6
 
7
7
  const init = process.env.INIT || 0
8
8
  const server = true
@@ -18,12 +18,12 @@ const serverConfig = {
18
18
  output: {
19
19
  //打包出口
20
20
  filename: `bundle.${version}.js`, //打包后的文件名
21
- path: path.resolve(__dirname, 'build'), //存放到根目录的build文件夹
21
+ path: path.resolve(__dirname, '../build'), //存放到根目录的build文件夹
22
22
  clean: true,
23
23
  libraryTarget: 'commonjs2'
24
24
  },
25
25
  externals: [
26
- '@loadable/component',
26
+ '@loadable/component',
27
27
  nodeExternals()
28
28
  ] //保持node中require的引用方式
29
29
  }
@@ -43,7 +43,7 @@ COPY --from=builder /app/public ./public
43
43
 
44
44
  # Copy scripts and config
45
45
  COPY --from=builder /app/scripts ./scripts
46
- COPY --from=builder /app/tsconfig.json ./
46
+ COPY --from=builder /app/tsconfig.json ./tsconfig.json
47
47
 
48
48
  # Change ownership
49
49
  RUN chown -R nodejs:nodejs /app
@@ -1,23 +1,28 @@
1
+ # 从 .env 文件读取环境变量(如果存在)
2
+ # 开发环境配置优先级:.env > docker-compose.dev.yml 默认值
3
+
1
4
  services:
2
5
  app:
3
6
  build:
4
- context: .
5
- dockerfile: Dockerfile.dev
7
+ context: ..
8
+ dockerfile: docker/Dockerfile.dev
6
9
  container_name: nsbp-app-dev
7
10
  ports:
8
11
  - "3001:3001"
9
12
  - "9229:9229" # Node.js debug port
10
13
  environment:
11
- - NODE_ENV=development
12
- - PORT=3001
14
+ - NODE_ENV=${NODE_ENV:-development}
15
+ - PORT=${PORT:-3001}
16
+ # 开发环境默认禁用速率限制,如需启用可在 .env 中设置
17
+ - ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-0}
13
18
  volumes:
14
19
  # Mount source code for hot reload
15
20
  - ./src:/app/src
16
21
  - ./public:/app/public
17
22
  - ./scripts:/app/scripts
18
- - ./webpack.base.js:/app/webpack.base.js
19
- - ./webpack.client.js:/app/webpack.client.js
20
- - ./webpack.server.js:/app/webpack.server.js
23
+ - ./config/webpack.base.js:/app/config/webpack.base.js
24
+ - ./config/webpack.client.js:/app/config/webpack.client.js
25
+ - ./config/webpack.server.js:/app/config/webpack.server.js
21
26
  - ./tsconfig.json:/app/tsconfig.json
22
27
  # Persist node_modules
23
28
  - node_modules:/app/node_modules
@@ -1,14 +1,18 @@
1
+ # 从 .env 文件读取环境变量(如果存在)
2
+ # 生产环境配置优先级:.env > docker-compose.yml 默认值
3
+
1
4
  services:
2
5
  app:
3
6
  build:
4
- context: .
5
- dockerfile: Dockerfile
7
+ context: ..
8
+ dockerfile: docker/Dockerfile
6
9
  container_name: nsbp-app
7
10
  ports:
8
11
  - "8091:3001"
9
12
  environment:
10
- - NODE_ENV=production
11
- - PORT=3001
13
+ - NODE_ENV=${NODE_ENV:-production}
14
+ - PORT=${PORT:-3001}
15
+ - ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-1}
12
16
  restart: unless-stopped
13
17
  healthcheck:
14
18
  test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
@@ -0,0 +1,346 @@
1
+ # NSBP 环境变量配置指南
2
+
3
+ ## 快速开始
4
+
5
+ ```bash
6
+ # 1. 复制环境变量模板
7
+ cp .env.example .env
8
+
9
+ # 2. 根据需要编辑 .env
10
+ nano .env
11
+
12
+ # 3. 开始开发或部署
13
+ pnpm run dev # 本地开发
14
+ docker-compose up -d # Docker 部署
15
+ ```
16
+
17
+ ---
18
+
19
+ ## 配置文件说明
20
+
21
+ ### 文件优先级
22
+
23
+ ```
24
+ .env.local (最高优先级) → .env → docker-compose.yml 默认值
25
+ ```
26
+
27
+ ### 文件列表
28
+
29
+ | 文件名 | 说明 | 提交到 Git | 使用场景 |
30
+ |-------|------|-----------|---------|
31
+ | `.env.example` | 环境变量模板 | ✅ 提交 | 新项目初始化 |
32
+ | `.env` | 默认环境配置 | ❌ 不提交 | 日常开发/部署 |
33
+ | `.env.development` | 开发环境配置 | ❌ 不提交 | 切换到开发环境 |
34
+ | `.env.production` | 生产环境配置 | ❌ 不提交 | 切换到生产环境 |
35
+ | `.env.local` | 本地敏感信息 | ❌ 不提交 | 存储密钥、密码等 |
36
+
37
+ ---
38
+
39
+ ## 快速切换环境
40
+
41
+ ### 使用 Makefile(推荐)
42
+
43
+ ```bash
44
+ # 切换到开发环境
45
+ make env-dev
46
+
47
+ # 切换到生产环境
48
+ make env-prod
49
+
50
+ # 创建本地配置文件
51
+ make env-local
52
+
53
+ # 查看当前配置
54
+ make show-env
55
+ ```
56
+
57
+ ### 手动方式
58
+
59
+ ```bash
60
+ # 切换到开发环境
61
+ cp .env.development .env
62
+
63
+ # 切换到生产环境
64
+ cp .env.production .env
65
+
66
+ # 创建本地配置
67
+ cp .env.example .env.local
68
+ ```
69
+
70
+ ---
71
+
72
+ ## 环境变量说明
73
+
74
+ ### 基础配置
75
+
76
+ ```bash
77
+ # 运行环境
78
+ NODE_ENV=development # 或 production
79
+
80
+ # 服务端口
81
+ PORT=3001
82
+
83
+ # 时区
84
+ TZ=Asia/Shanghai
85
+ ```
86
+
87
+ ### 安全配置
88
+
89
+ ```bash
90
+ # 启用速率限制
91
+ ENABLE_RATE_LIMIT=1 # 1=启用,0=禁用
92
+ ```
93
+
94
+ **建议:**
95
+ - ✅ 开发环境:`ENABLE_RATE_LIMIT=0`(不影响开发效率)
96
+ - ✅ 生产环境:`ENABLE_RATE_LIMIT=1`(防止 DDoS 攻击)
97
+
98
+ ### 调试配置
99
+
100
+ ```bash
101
+ # 启用详细日志
102
+ DEBUG=nsbp:*
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 使用场景
108
+
109
+ ### 场景 1:新项目初始化
110
+
111
+ ```bash
112
+ # 1. 克隆项目
113
+ git clone <repository-url>
114
+ cd nsbp
115
+
116
+ # 2. 复制环境变量模板
117
+ cp .env.example .env
118
+
119
+ # 3. 安装依赖
120
+ pnpm install
121
+
122
+ # 4. 启动开发环境
123
+ pnpm run dev
124
+ ```
125
+
126
+ ### 场景 2:日常开发
127
+
128
+ ```bash
129
+ # 使用开发环境配置
130
+ make env-dev
131
+
132
+ # 启动开发环境
133
+ pnpm run dev
134
+ ```
135
+
136
+ ### 场景 3:Docker 部署
137
+
138
+ ```bash
139
+ # 切换到生产环境
140
+ make env-prod
141
+
142
+ # 启动 Docker 容器
143
+ docker-compose up -d
144
+
145
+ # 查看日志
146
+ docker-compose logs -f
147
+ ```
148
+
149
+ ### 场景 4:敏感信息管理
150
+
151
+ ```bash
152
+ # 1. 创建本地配置文件
153
+ make env-local
154
+
155
+ # 2. 编辑 .env.local 添加敏感信息
156
+ nano .env.local
157
+
158
+ # 添加内容:
159
+ # DATABASE_URL=postgresql://user:pass@localhost:5432/db
160
+ # API_SECRET=your-secret-key
161
+ # JWT_SECRET=jwt-secret-key
162
+
163
+ # .env.local 会自动覆盖 .env 中的同名变量
164
+ ```
165
+
166
+ ---
167
+
168
+ ## 最佳实践
169
+
170
+ ### ✅ 推荐做法
171
+
172
+ 1. **始终使用 .env 文件**
173
+ ```bash
174
+ # 不要在代码中硬编码
175
+ const PORT = process.env.PORT || 3001 # ✅
176
+ const PORT = 3001 # ❌
177
+ ```
178
+
179
+ 2. **分离敏感信息**
180
+ ```bash
181
+ # .env - 非敏感配置(可以分享给团队)
182
+ NODE_ENV=development
183
+ PORT=3001
184
+ ENABLE_RATE_LIMIT=0
185
+
186
+ # .env.local - 敏感配置(个人使用)
187
+ DATABASE_URL=postgresql://localhost/db
188
+ API_KEY=secret-key-123
189
+ ```
190
+
191
+ 3. **提供 .env.example**
192
+ ```bash
193
+ # .env.example - 示例配置(提交到 Git)
194
+ NODE_ENV=development
195
+ PORT=3001
196
+ ENABLE_RATE_LIMIT=0
197
+ # API_KEY=your-api-key # 提供示例,不包含真实值
198
+ ```
199
+
200
+ 4. **使用环境前缀**
201
+ ```bash
202
+ # 命名规范
203
+ NSBP_NODE_ENV=development
204
+ NSBP_PORT=3001
205
+ NSBP_ENABLE_RATE_LIMIT=0
206
+ ```
207
+
208
+ ### ❌ 避免做法
209
+
210
+ 1. **不要提交 .env 到 Git**
211
+ ```bash
212
+ # .gitignore 已包含
213
+ .env
214
+ .env.local
215
+ .env.*.local
216
+ ```
217
+
218
+ 2. **不要在代码中硬编码敏感信息**
219
+ ```javascript
220
+ // ❌ 错误做法
221
+ const dbPassword = "my-password-123"
222
+
223
+ // ✅ 正确做法
224
+ const dbPassword = process.env.DB_PASSWORD
225
+ ```
226
+
227
+ 3. **不要在 .env.example 中包含真实值**
228
+ ```bash
229
+ # .env.example - 只提供示例
230
+ API_KEY=your-api-key-here # ✅
231
+ API_KEY=sk-1234567890abcdef # ❌
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Docker Compose 集成
237
+
238
+ ### 自动读取 .env
239
+
240
+ Docker Compose 会自动读取项目根目录下的 `.env` 文件:
241
+
242
+ ```yaml
243
+ # docker-compose.yml
244
+ services:
245
+ app:
246
+ environment:
247
+ - NODE_ENV=${NODE_ENV:-production}
248
+ - PORT=${PORT:-3001}
249
+ - ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-1}
250
+ ```
251
+
252
+ ### 使用方式
253
+
254
+ ```bash
255
+ # 1. 创建 .env 文件
256
+ cp .env.production .env
257
+
258
+ # 2. Docker Compose 自动读取
259
+ docker-compose up -d
260
+
261
+ # 3. 验证环境变量
262
+ docker-compose exec app env | grep NODE_ENV
263
+ ```
264
+
265
+ ---
266
+
267
+ ## 故障排除
268
+
269
+ ### 问题 1:环境变量未生效
270
+
271
+ **检查步骤:**
272
+ ```bash
273
+ # 1. 检查 .env 文件是否存在
274
+ ls -la .env
275
+
276
+ # 2. 查看文件内容
277
+ cat .env
278
+
279
+ # 3. 验证格式(等号两边不要有空格)
280
+ NODE_ENV=development # ✅
281
+ NODE_ENV = development # ❌
282
+
283
+ # 4. 重启服务
284
+ docker-compose restart
285
+ ```
286
+
287
+ ### 问题 2:敏感信息泄露
288
+
289
+ **预防措施:**
290
+ ```bash
291
+ # 1. 检查 .gitignore
292
+ cat .gitignore | grep .env
293
+
294
+ # 2. 验证文件未被提交
295
+ git ls-files | grep .env
296
+
297
+ # 3. 如果已提交,从历史记录中移除
298
+ git filter-branch --force --index-filter \
299
+ 'git rm --cached --ignore-unmatch .env'
300
+ ```
301
+
302
+ ### 问题 3:环境变量优先级混乱
303
+
304
+ **验证方法:**
305
+ ```bash
306
+ # 1. 显示容器中的环境变量
307
+ docker-compose exec app env | sort
308
+
309
+ # 2. 查看实际生效的值
310
+ docker-compose exec app sh -c 'echo $NODE_ENV'
311
+
312
+ # 3. 检查 .env.local 是否覆盖了预期值
313
+ cat .env.local | grep NODE_ENV
314
+ ```
315
+
316
+ ---
317
+
318
+ ## 常用命令速查
319
+
320
+ ```bash
321
+ # 查看当前配置
322
+ make show-env
323
+
324
+ # 切换开发环境
325
+ make env-dev
326
+
327
+ # 切换生产环境
328
+ make env-prod
329
+
330
+ # 创建本地配置
331
+ make env-local
332
+
333
+ # 查看容器环境变量
334
+ docker-compose exec app env
335
+
336
+ # 验证特定变量
337
+ docker-compose exec app sh -c 'echo $ENABLE_RATE_LIMIT'
338
+ ```
339
+
340
+ ---
341
+
342
+ ## 参考资源
343
+
344
+ - [Docker Compose 环境变量](https://docs.docker.com/compose/environment-variables/)
345
+ - [Node.js process.env](https://nodejs.org/api/process.html#process_process_env)
346
+ - [十二因子应用](https://12factor.net/)
@@ -0,0 +1,99 @@
1
+ # Docker 快速启动指南
2
+
3
+ 🌐 **Online Demo**: [https://nsbp.erishen.cn/](https://nsbp.erishen.cn/)
4
+
5
+ ## 5 分钟快速开始
6
+
7
+ ### 生产环境(推荐用于生产部署)
8
+
9
+ ```bash
10
+ # 1. 构建并启动
11
+ docker-compose up -d
12
+
13
+ # 2. 查看状态
14
+ docker-compose ps
15
+
16
+ # 3. 查看日志(可选)
17
+ docker-compose logs -f
18
+
19
+ # 4. 访问应用
20
+ open http://localhost:3001
21
+ ```
22
+
23
+ 完成!🎉
24
+
25
+ ### 开发环境(推荐用于开发)
26
+
27
+ ```bash
28
+ # 1. 构建并启动(前台运行,可查看构建日志)
29
+ docker-compose -f docker-compose.dev.yml up --build
30
+
31
+ # 2. 等待看到 "Server listening on port 3001"
32
+ # (首次启动需要 1-3 分钟进行构建)
33
+
34
+ # 3. 访问应用
35
+ open http://localhost:3001
36
+
37
+ # 4. 修改代码,自动热重载
38
+ ```
39
+
40
+ **提示:** 如果想在后台运行:
41
+ ```bash
42
+ docker-compose -f docker-compose.dev.yml up -d --build
43
+ docker-compose -f docker-compose.dev.yml logs -f
44
+ ```
45
+
46
+ ## 常用命令
47
+
48
+ ### 生产环境
49
+ ```bash
50
+ make prod # 启动
51
+ make logs # 查看日志
52
+ make restart # 重启
53
+ make down # 停止
54
+ make clean # 完全清理
55
+ ```
56
+
57
+ ### 开发环境
58
+ ```bash
59
+ make dev # 启动(带热重载)
60
+ make logs-dev # 查看日志
61
+ make restart-dev # 重启
62
+ ```
63
+
64
+ ### 通用
65
+ ```bash
66
+ make help # 查看所有命令
67
+ make shell # 进入生产容器
68
+ make shell-dev # 进入开发容器
69
+ ```
70
+
71
+ ## 验证安装
72
+
73
+ 检查 Docker 是否正确安装:
74
+ ```bash
75
+ docker --version
76
+ docker-compose --version
77
+ ```
78
+
79
+ 测试配置:
80
+ ```bash
81
+ ./scripts/verify-dev.sh
82
+ ```
83
+
84
+ ## 遇到问题?
85
+
86
+ - 查看 README.md 中的 Docker 部署章节
87
+ - 运行 `./scripts/verify-dev.sh` 验证开发环境状态
88
+ - 确保 Docker 守护进程正在运行
89
+
90
+ ## 目录说明
91
+
92
+ - `Dockerfile` - 生产环境镜像
93
+ - `Dockerfile.dev` - 开发环境镜像
94
+ - `docker-compose.yml` - 生产环境配置
95
+ - `docker-compose.dev.yml` - 开发环境配置
96
+ - `Makefile` - 快捷命令
97
+ - `scripts/verify-dev.sh` - 开发环境验证脚本
98
+ - `README.md` - 完整文档
99
+ - `QUICKSTART.md` - 本文档
@@ -23,6 +23,8 @@ public/*.json
23
23
  .env
24
24
  .env.local
25
25
  .env.*.local
26
+ .env.development
27
+ .env.production
26
28
 
27
29
  # Logs
28
30
  logs
@@ -3,16 +3,16 @@
3
3
  "version": "1.0.0",
4
4
  "description": "node react ssr by webpack",
5
5
  "main": "index.js",
6
- "homepage": "https://nsbp.erishen.cn/",
6
+ "homepage": "https://nsbp.erishen.cn",
7
7
  "scripts": {
8
8
  "dev": "npm-run-all -l -s dev:init -p dev:build:*",
9
- "dev:init": "cross-env INIT=1 webpack --config webpack.server.js --mode development",
10
- "dev:build:server": "webpack --config webpack.server.js --mode development --watch",
11
- "dev:build:client": "webpack --config webpack.client.js --mode development --watch",
9
+ "dev:init": "cross-env INIT=1 webpack --config config/webpack.server.js --mode development",
10
+ "dev:build:server": "webpack --config config/webpack.server.js --mode development --watch",
11
+ "dev:build:client": "webpack --config config/webpack.client.js --mode development --watch",
12
12
  "dev:build:start": "node ./scripts/start.js",
13
13
  "build": "pnpm run clean && npm-run-all -l -p build:**",
14
- "build:server": "webpack --config webpack.server.js --mode production",
15
- "build:client": "webpack --config webpack.client.js --mode production",
14
+ "build:server": "webpack --config config/webpack.server.js --mode production",
15
+ "build:client": "webpack --config config/webpack.client.js --mode production",
16
16
  "start": "node ./scripts/start.js",
17
17
  "clean": "rimraf build && rimraf public/js && rimraf public/css && rimraf public/client.* && rimraf public/*.js && rimraf public/*.js.map && rimraf public/*.txt && rimraf public/*.json && rimraf .temp_cache",
18
18
  "format": "prettier --write **/*.{js,css,less,scss,ts,tsx}",
@@ -37,7 +37,9 @@
37
37
  "@reduxjs/toolkit": "^2.11.2",
38
38
  "axios": "^1.7.0",
39
39
  "express": "^5.2.1",
40
+ "express-rate-limit": "^8.2.0",
40
41
  "framer-motion": "^12.25.0",
42
+ "helmet": "^8.1.0",
41
43
  "lodash": "^4.17.21",
42
44
  "probe-image-size": "^7.1.0",
43
45
  "react": "^19.2.3",
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
2
+ <defs>
3
+ <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#2563eb" />
5
+ <stop offset="100%" stop-color="#1d4ed8" />
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="100" height="100" rx="20" fill="url(#gradient)" />
9
+ <text x="50" y="68" font-family="Arial, sans-serif" font-size="60" font-weight="bold" text-anchor="middle" fill="white">N</text>
10
+ </svg>
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "Nsbp.js - 轻量级 React SSR 框架",
3
+ "short_name": "Nsbp.js",
4
+ "description": "轻量级 React SSR 框架,专为低资源部署与高度可定制场景而生",
5
+ "icons": [
6
+ {
7
+ "src": "/favicon-192x192.png",
8
+ "sizes": "192x192",
9
+ "type": "image/png"
10
+ },
11
+ {
12
+ "src": "/favicon-512x512.png",
13
+ "sizes": "512x512",
14
+ "type": "image/png"
15
+ }
16
+ ],
17
+ "theme_color": "#2563eb",
18
+ "background_color": "#ffffff",
19
+ "display": "standalone"
20
+ }
@@ -20,7 +20,7 @@ else
20
20
  echo ""
21
21
  echo "启动命令:"
22
22
  echo " make dev"
23
- echo " docker-compose -f docker-compose.dev.yml up -d --build"
23
+ echo " docker-compose -f docker/docker-compose.dev.yml up -d --build"
24
24
  exit 1
25
25
  fi
26
26
 
@@ -35,7 +35,7 @@ fi
35
35
 
36
36
  echo ""
37
37
  echo "3. 检查权限错误..."
38
- if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "EACCES"; then
38
+ if docker-compose -f docker/docker-compose.dev.yml logs 2>&1 | grep -q "EACCES"; then
39
39
  echo -e "${RED}❌ 发现权限错误${NC}"
40
40
  echo ""
41
41
  echo "最近的权限错误:"
@@ -46,7 +46,7 @@ fi
46
46
 
47
47
  echo ""
48
48
  echo "4. 检查构建状态..."
49
- if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "compiled successfully"; then
49
+ if docker-compose -f docker/docker-compose.dev.yml logs 2>&1 | grep -q "compiled successfully"; then
50
50
  echo -e "${GREEN}✅ 构建完成${NC}"
51
51
  else
52
52
  echo -e "${YELLOW}⚠️ 构建中或未开始${NC}"
@@ -54,7 +54,7 @@ fi
54
54
 
55
55
  echo ""
56
56
  echo "5. 检查服务器监听..."
57
- if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "listening"; then
57
+ if docker-compose -f docker/docker-compose.dev.yml logs 2>&1 | grep -q "listening"; then
58
58
  echo -e "${GREEN}✅ 服务器正在监听${NC}"
59
59
  else
60
60
  echo -e "${YELLOW}⚠️ 服务器尚未启动监听${NC}"
@@ -69,9 +69,9 @@ echo "访问应用:"
69
69
  echo " http://localhost:3001"
70
70
  echo ""
71
71
  echo "查看日志:"
72
- echo " docker-compose -f docker-compose.dev.yml logs -f"
72
+ echo " docker-compose -f docker/docker-compose.dev.yml logs -f"
73
73
  echo ""
74
74
  echo "停止服务:"
75
75
  echo " make down"
76
- echo " docker-compose -f docker-compose.dev.yml down"
76
+ echo " docker-compose -f docker/docker-compose.dev.yml down"
77
77
  echo ""
@@ -0,0 +1,124 @@
1
+ #!/bin/bash
2
+
3
+ echo "========================================="
4
+ echo "NSBP 安全功能验证"
5
+ echo "========================================="
6
+ echo ""
7
+
8
+ GREEN='\033[0;32m'
9
+ RED='\033[0;31m'
10
+ YELLOW='\033[1;33m'
11
+ NC='\033[0m'
12
+
13
+ # 检查依赖
14
+ echo "1. 检查安全依赖安装..."
15
+ if grep -q '"helmet"' package.json && grep -q '"express-rate-limit"' package.json; then
16
+ echo -e "${GREEN}✅ helmet 和 express-rate-limit 已安装${NC}"
17
+ else
18
+ echo -e "${RED}❌ 缺少安全依赖${NC}"
19
+ exit 1
20
+ fi
21
+
22
+ echo ""
23
+
24
+ # 检查服务器代码
25
+ echo "2. 检查服务器代码安全配置..."
26
+ if grep -q "helmet(" src/server/index.ts; then
27
+ echo -e "${GREEN}✅ Helmet 已启用${NC}"
28
+ else
29
+ echo -e "${RED}❌ Helmet 未配置${NC}"
30
+ fi
31
+
32
+ if grep -q "rateLimit" src/server/index.ts; then
33
+ echo -e "${GREEN}✅ 速率限制已配置(可选)${NC}"
34
+ else
35
+ echo -e "${RED}❌ 速率限制未配置${NC}"
36
+ fi
37
+
38
+ if grep -q "dotfiles: 'ignore'" src/server/index.ts; then
39
+ echo -e "${GREEN}✅ dotfiles 访问已禁用${NC}"
40
+ else
41
+ echo -e "${RED}⚠️ dotfiles 配置需要检查${NC}"
42
+ fi
43
+
44
+ if grep -q "disable('x-powered-by')" src/server/index.ts; then
45
+ echo -e "${GREEN}✅ X-Powered-By 已隐藏${NC}"
46
+ else
47
+ echo -e "${RED}❌ X-Powered-By 未隐藏${NC}"
48
+ fi
49
+
50
+ if grep -q "express.json.*limit" src/server/index.ts && grep -q "express.urlencoded.*limit" src/server/index.ts; then
51
+ echo -e "${GREEN}✅ 请求体大小限制已配置${NC}"
52
+ else
53
+ echo -e "${RED}❌ 请求体大小限制未配置${NC}"
54
+ fi
55
+
56
+ echo ""
57
+
58
+ # 检查 CSP 配置
59
+ echo "3. 检查 Content Security Policy..."
60
+ if grep -q "contentSecurityPolicy" src/server/index.ts; then
61
+ echo -e "${GREEN}✅ CSP 已配置${NC}"
62
+ if grep -q "defaultSrc.*'self'" src/server/index.ts; then
63
+ echo -e "${GREEN} - default-src: 'self'${NC}"
64
+ fi
65
+ if grep -q "scriptSrc" src/server/index.ts; then
66
+ echo -e "${GREEN} - script-src 已配置${NC}"
67
+ fi
68
+ if grep -q "styleSrc" src/server/index.ts; then
69
+ echo -e "${GREEN} - style-src 已配置${NC}"
70
+ fi
71
+ if grep -q "imgSrc.*https:" src/server/index.ts; then
72
+ echo -e "${GREEN} - img-src 允许 HTTPS${NC}"
73
+ fi
74
+ else
75
+ echo -e "${RED}❌ CSP 未配置${NC}"
76
+ fi
77
+
78
+ echo ""
79
+
80
+ # 检查文档
81
+ echo "4. 检查安全文档..."
82
+ if grep -q "## 安全特性" README.md; then
83
+ echo -e "${GREEN}✅ 安全章节已添加到 README${NC}"
84
+ else
85
+ echo -e "${YELLOW}⚠️ 建议添加安全章节到 README${NC}"
86
+ fi
87
+
88
+ echo ""
89
+
90
+ # 统计
91
+ echo "========================================="
92
+ echo "安全配置统计"
93
+ echo "========================================="
94
+
95
+ TOTAL_CHECKS=7
96
+ PASSED_CHECKS=0
97
+
98
+ # 统计通过项
99
+ grep -q '"helmet"' package.json && grep -q '"express-rate-limit"' package.json && ((PASSED_CHECKS++))
100
+ grep -q "helmet(" src/server/index.ts && ((PASSED_CHECKS++))
101
+ grep -q "dotfiles: 'ignore'" src/server/index.ts && ((PASSED_CHECKS++))
102
+ grep -q "disable('x-powered-by')" src/server/index.ts && ((PASSED_CHECKS++))
103
+ grep -q "express.json.*limit" src/server/index.ts && ((PASSED_CHECKS++))
104
+ grep -q "contentSecurityPolicy" src/server/index.ts && ((PASSED_CHECKS++))
105
+ grep -q "## 安全特性" README.md && ((PASSED_CHECKS++))
106
+
107
+ SCORE=$(( PASSED_CHECKS * 100 / TOTAL_CHECKS ))
108
+
109
+ echo -e "通过率: ${PASSED_CHECKS}/${TOTAL_CHECKS} (${YELLOW}${SCORE}%${NC})"
110
+ echo ""
111
+
112
+ if [ $SCORE -eq 100 ]; then
113
+ echo -e "${GREEN}🎉 所有安全检查通过!${NC}"
114
+ echo "项目已达到生产级安全标准。"
115
+ elif [ $SCORE -ge 70 ]; then
116
+ echo -e "${YELLOW}✅ 安全配置良好${NC}"
117
+ echo "建议检查未通过的项目。"
118
+ else
119
+ echo -e "${RED}⚠️ 安全配置需要改进${NC}"
120
+ echo "请检查上述未通过的项目。"
121
+ fi
122
+
123
+ echo ""
124
+ echo "========================================="
@@ -1,12 +1,62 @@
1
1
  import express from 'express'
2
+ import helmet from 'helmet'
3
+ import rateLimit from 'express-rate-limit'
2
4
  import { render } from './utils'
3
5
  import { getPhotoWH, getPhotoMenu } from './photo'
4
6
  import { useCurrentFlag, outPhotoDicPath } from '../utils/config'
5
7
 
6
8
  const app = express()
7
9
 
8
- app.use(express.static('public', { dotfiles: 'allow' }))
9
- !useCurrentFlag && app.use(express.static(outPhotoDicPath, { dotfiles: 'allow' }))
10
+ // 1. Security headers (helmet)
11
+ app.use(helmet({
12
+ contentSecurityPolicy: {
13
+ directives: {
14
+ defaultSrc: ["'self'"],
15
+ scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
16
+ styleSrc: ["'self'", "'unsafe-inline'"],
17
+ imgSrc: ["'self'", "data:", "https:"],
18
+ connectSrc: ["'self'", "https:"],
19
+ fontSrc: ["'self'", "data:"],
20
+ objectSrc: ["'none'"],
21
+ mediaSrc: ["'self'"],
22
+ frameSrc: ["'none'"],
23
+ },
24
+ },
25
+ crossOriginEmbedderPolicy: false, // Allow inline scripts for SSR
26
+ crossOriginOpenerPolicy: false, // Allow window.open for development
27
+ }))
28
+
29
+ // 2. Hide X-Powered-By header
30
+ app.disable('x-powered-by')
31
+
32
+ // 3. Rate limiting (optional, controlled by environment variable)
33
+ if (process.env.ENABLE_RATE_LIMIT === '1') {
34
+ const limiter = rateLimit({
35
+ windowMs: 15 * 60 * 1000, // 15 minutes
36
+ max: 100, // Limit each IP to 100 requests per windowMs
37
+ message: 'Too many requests from this IP, please try again later.',
38
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
39
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
40
+ })
41
+ app.use('/api', limiter)
42
+ console.log('🛡️ Rate limiting enabled for /api routes')
43
+ }
44
+
45
+ // 4. Static file serving (disable dotfiles access)
46
+ app.use(express.static('public', {
47
+ dotfiles: 'ignore',
48
+ setHeaders: (res, filePath) => {
49
+ // Cache static assets for 1 year
50
+ if (filePath.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/)) {
51
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
52
+ }
53
+ }
54
+ }))
55
+ !useCurrentFlag && app.use(express.static(outPhotoDicPath, { dotfiles: 'ignore' }))
56
+
57
+ // 5. Body parsing with size limits
58
+ app.use(express.json({ limit: '10mb' }))
59
+ app.use(express.urlencoded({ limit: '10mb', extended: true }))
10
60
 
11
61
  //使用express提供的static中间件,中间件会将所有静态文件的路由指向public文件夹
12
62
 
@@ -27,4 +77,8 @@ app.use((req, res) => {
27
77
  const PORT = process.env.PORT || 3001
28
78
  app.listen(PORT, () => {
29
79
  console.log(`Server listening on port ${PORT}`)
80
+ console.log(`🔒 Security headers enabled`)
81
+ if (process.env.ENABLE_RATE_LIMIT === '1') {
82
+ console.log(`🚦 Rate limiting active`)
83
+ }
30
84
  })
@@ -116,6 +116,13 @@ export const render = (req: any, res: any) => {
116
116
  <html>
117
117
  <head>
118
118
  <meta charset="utf-8">
119
+ <link rel="icon" type="image/x-icon" href="/favicon.ico">
120
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
121
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
122
+ <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
123
+ <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
124
+ <link rel="manifest" href="/site.webmanifest">
125
+ <meta name="theme-color" content="#2563eb">
119
126
  ${helmet?.title?.toString()}
120
127
  ${helmet?.meta?.toString()}
121
128
  ${styleTags}