nodebbs 0.0.9 → 0.1.0

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.
@@ -3,22 +3,37 @@ services:
3
3
  postgres:
4
4
  image: postgres:16-alpine
5
5
  container_name: nodebbs-postgres
6
- restart: unless-stopped
6
+ restart: always
7
7
  environment:
8
8
  POSTGRES_USER: postgres
9
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
9
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
10
10
  POSTGRES_DB: ${POSTGRES_DB:-nodebbs}
11
- TZ: Asia/Shanghai
11
+ TZ: ${TZ:-Asia/Shanghai}
12
12
  volumes:
13
13
  - postgres_data:/var/lib/postgresql/data
14
- - ${INIT_DB_PATH:-./scripts/init-db.sql}:/docker-entrypoint-initdb.d/init.sql:ro
15
- ports:
16
- - "${POSTGRES_PORT:-5432}:5432"
14
+ # 生产环境默认不暴露数据库端口到主机,只在 Docker 网络内部访问
15
+ # 如果需要外部访问 (如开发调试),可以将下面两行取消注释
16
+ # ports:
17
+ # - "${POSTGRES_PORT:-5432}:5432"
17
18
  healthcheck:
18
19
  test: ["CMD-SHELL", "pg_isready -U postgres"]
19
- interval: 10s
20
- timeout: 5s
20
+ interval: 30s
21
+ timeout: 10s
21
22
  retries: 5
23
+ start_period: 40s
24
+ deploy:
25
+ resources:
26
+ limits:
27
+ cpus: '1'
28
+ memory: 512M
29
+ reservations:
30
+ cpus: '0.25'
31
+ memory: 256M
32
+ logging:
33
+ driver: "json-file"
34
+ options:
35
+ max-size: "10m"
36
+ max-file: "3"
22
37
  networks:
23
38
  - nodebbs-network
24
39
 
@@ -26,45 +41,62 @@ services:
26
41
  redis:
27
42
  image: redis:7-alpine
28
43
  container_name: nodebbs-redis
29
- restart: unless-stopped
30
- command: redis-server --requirepass ${REDIS_PASSWORD:-redis_password} --appendonly yes
31
- environment:
32
- TZ: Asia/Shanghai
44
+ restart: always
45
+ command: >
46
+ redis-server
47
+ --requirepass ${REDIS_PASSWORD}
48
+ --appendonly yes
49
+ --appendfsync everysec
50
+ --maxmemory 256mb
51
+ --maxmemory-policy allkeys-lru
33
52
  volumes:
34
53
  - redis_data:/data
35
- ports:
36
- - "${REDIS_PORT:-6379}:6379"
54
+ # 生产环境默认不暴露 Redis 端口到主机
55
+ # ports:
56
+ # - "${REDIS_PORT:-6379}:6379"
37
57
  healthcheck:
38
58
  test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
39
- interval: 10s
40
- timeout: 5s
59
+ interval: 30s
60
+ timeout: 10s
41
61
  retries: 5
62
+ start_period: 20s
63
+ deploy:
64
+ resources:
65
+ limits:
66
+ cpus: '0.5'
67
+ memory: 256M
68
+ reservations:
69
+ cpus: '0.1'
70
+ memory: 128M
71
+ logging:
72
+ driver: "json-file"
73
+ options:
74
+ max-size: "10m"
75
+ max-file: "3"
42
76
  networks:
43
77
  - nodebbs-network
44
78
 
45
79
  # API 服务
46
80
  api:
47
- build:
48
- context: . # 从 monorepo 根目录构建(turbo prune 需要完整的 workspace)
49
- dockerfile: apps/api/Dockerfile
81
+ image: ${API_IMAGE:-ghcr.io/aiprojecthub/nodebbs-api:latest}
50
82
  container_name: nodebbs-api
51
- restart: unless-stopped
83
+ restart: always
52
84
  environment:
53
85
  NODE_ENV: production
54
86
  APP_NAME: ${APP_NAME:-nodebbs}
55
87
  HOST: 0.0.0.0
56
88
  PORT: 7100
57
- DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres_password}@postgres:5432/${POSTGRES_DB:-nodebbs}
58
- REDIS_URL: redis://default:${REDIS_PASSWORD:-redis_password}@redis:6379/0
59
- USER_CACHE_TTL: ${USER_CACHE_TTL:-120}
60
- JWT_SECRET: ${JWT_SECRET:-change-this-to-a-secure-random-string-in-production}
89
+ DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-nodebbs}
90
+ REDIS_URL: redis://default:${REDIS_PASSWORD}@redis:6379/0
91
+ USER_CACHE_TTL: ${USER_CACHE_TTL:-300}
92
+ JWT_SECRET: ${JWT_SECRET}
61
93
  JWT_ACCESS_TOKEN_EXPIRES_IN: ${JWT_ACCESS_TOKEN_EXPIRES_IN:-1y}
62
94
  CORS_ORIGIN: ${CORS_ORIGIN:-*}
63
95
  APP_URL: ${APP_URL:-http://localhost:3100}
64
- TZ: Asia/Shanghai
96
+ TZ: ${TZ:-Asia/Shanghai}
97
+ NODE_OPTIONS: "--max-old-space-size=512"
65
98
  volumes:
66
99
  - api_uploads:/app/apps/api/uploads
67
- - ./apps/api/src:/app/apps/api/src:ro
68
100
  ports:
69
101
  - "${API_PORT:-7100}:7100"
70
102
  depends_on:
@@ -78,26 +110,35 @@ services:
78
110
  timeout: 10s
79
111
  retries: 3
80
112
  start_period: 40s
113
+ deploy:
114
+ resources:
115
+ limits:
116
+ cpus: '1'
117
+ memory: 768M
118
+ reservations:
119
+ cpus: '0.3'
120
+ memory: 384M
121
+ logging:
122
+ driver: "json-file"
123
+ options:
124
+ max-size: "20m"
125
+ max-file: "5"
81
126
  networks:
82
127
  - nodebbs-network
83
128
 
84
129
  # Web 前端服务
85
130
  web:
86
- build:
87
- context: . # 从 monorepo 根目录构建(turbo prune 需要完整的 workspace)
88
- dockerfile: apps/web/Dockerfile
89
- args:
90
- NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:7100}
91
- NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3100}
131
+ image: ${WEB_IMAGE:-ghcr.io/aiprojecthub/nodebbs-web:latest}
92
132
  container_name: nodebbs-web
93
- restart: unless-stopped
133
+ restart: always
94
134
  environment:
95
135
  NODE_ENV: production
96
136
  APP_NAME: ${APP_NAME:-nodebbs}
97
137
  PORT: 3100
98
138
  NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:7100}
99
139
  NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3100}
100
- TZ: Asia/Shanghai
140
+ TZ: ${TZ:-Asia/Shanghai}
141
+ NODE_OPTIONS: "--max-old-space-size=512"
101
142
  ports:
102
143
  - "${WEB_PORT:-3100}:3100"
103
144
  depends_on:
@@ -109,6 +150,19 @@ services:
109
150
  timeout: 10s
110
151
  retries: 3
111
152
  start_period: 40s
153
+ deploy:
154
+ resources:
155
+ limits:
156
+ cpus: '1'
157
+ memory: 768M
158
+ reservations:
159
+ cpus: '0.3'
160
+ memory: 384M
161
+ logging:
162
+ driver: "json-file"
163
+ options:
164
+ max-size: "20m"
165
+ max-file: "5"
112
166
  networks:
113
167
  - nodebbs-network
114
168
 
@@ -125,3 +179,6 @@ volumes:
125
179
  networks:
126
180
  nodebbs-network:
127
181
  driver: bridge
182
+ ipam:
183
+ config:
184
+ - subnet: 172.28.0.0/16
@@ -1,13 +1,27 @@
1
1
  # ========================================
2
- # NodeBBS Docker Compose 环境变量配置
2
+ # NodeBBS 部署环境变量配置示例
3
3
  # ========================================
4
4
 
5
- # 应用名称
5
+ # ========================================
6
+ # 基础配置
7
+ # ========================================
8
+ # 应用名称(用于 Docker 容器前缀)
6
9
  APP_NAME=nodebbs
7
10
 
11
+ # 部署环境 (prod, dev)
12
+ NODE_ENV=production
13
+
14
+ # 镜像配置
15
+ # 默认为 GitHub Container Registry
16
+ # 注意:使用 `nodebbs start` 时,可以选择版本 tag 覆盖此处的默认 latest tag
17
+ # 如果需要固定特定版本 (如 v1.0),请修改以下配置或在部署时输入对应的 tag
18
+ API_IMAGE=ghcr.io/aiprojecthub/nodebbs-api:latest
19
+ WEB_IMAGE=ghcr.io/aiprojecthub/nodebbs-web:latest
20
+
8
21
  # ========================================
9
22
  # 数据库配置
10
23
  # ========================================
24
+ # 务必修改为强密码!
11
25
  POSTGRES_PASSWORD=your_secure_postgres_password_here
12
26
  POSTGRES_DB=nodebbs
13
27
  POSTGRES_PORT=5432
@@ -15,6 +29,7 @@ POSTGRES_PORT=5432
15
29
  # ========================================
16
30
  # Redis 配置
17
31
  # ========================================
32
+ # 务必修改为强密码!
18
33
  REDIS_PASSWORD=your_secure_redis_password_here
19
34
  REDIS_PORT=6379
20
35
 
@@ -24,8 +39,8 @@ REDIS_PORT=6379
24
39
  API_PORT=7100
25
40
 
26
41
  # 用户缓存 TTL(秒)
27
- # 开发环境: 30-60, 生产环境: 120-300
28
- USER_CACHE_TTL=120
42
+ # 生产环境建议: 120-300
43
+ USER_CACHE_TTL=300
29
44
 
30
45
  # JWT 配置
31
46
  # 使用 `openssl rand -base64 32` 生成安全的密钥
@@ -37,6 +52,7 @@ JWT_ACCESS_TOKEN_EXPIRES_IN=1y
37
52
  CORS_ORIGIN=*
38
53
 
39
54
  # 应用 URL(OAuth 回调使用)
55
+ # 生产环境请修改为公网域名
40
56
  APP_URL=http://localhost:3100
41
57
 
42
58
  # ========================================
@@ -45,17 +61,16 @@ APP_URL=http://localhost:3100
45
61
  WEB_PORT=3100
46
62
 
47
63
  # API 地址(公网访问地址)
48
- # 使用 docker 部署必须指定 IP 或域名(避免SSR跨容器通信问题)
49
- # 开发环境: http://192.168.0.100:7100
50
- # 生产环境: https://api.yourdomain.com
51
- NEXT_PUBLIC_API_URL=http://192.168.0.100:7100
64
+ # 生产环境请修改为公网域名,例如: https://api.yourdomain.com
65
+ # 或者是 Nginx 反向代理后的地址,例如: https://yourdomain.com/api
66
+ NEXT_PUBLIC_API_URL=http://localhost:7100
52
67
 
53
68
  # 应用 URL(公网访问地址)
54
- # 开发环境: http://localhost:3100
55
- # 生产环境: https://yourdomain.com
69
+ # 生产环境请修改为公网域名,例如: https://yourdomain.com
56
70
  NEXT_PUBLIC_APP_URL=http://localhost:3100
57
71
 
58
72
  # ========================================
59
- # 时区配置
73
+ # 其他配置
60
74
  # ========================================
75
+ # 时区
61
76
  TZ=Asia/Shanghai
@@ -5,7 +5,7 @@
5
5
  * - 如果存在,则优先使用项目根目录的配置。
6
6
  * - 如果不存在,则使用 CLI 内置的模板文件。
7
7
  *
8
- * @param env - 运行环境 ('production' | 'lowmem' | 'basic')
8
+ * @param env - 运行环境 ('production' | 'lowmem')
9
9
  * @returns 对象包含文件路径数组和是否使用内置模板的标志
10
10
  */
11
11
  export declare function getComposeFiles(env: string): Promise<{
@@ -12,7 +12,7 @@ const fileExists = promisify(exists);
12
12
  * - 如果存在,则优先使用项目根目录的配置。
13
13
  * - 如果不存在,则使用 CLI 内置的模板文件。
14
14
  *
15
- * @param env - 运行环境 ('production' | 'lowmem' | 'basic')
15
+ * @param env - 运行环境 ('production' | 'lowmem')
16
16
  * @returns 对象包含文件路径数组和是否使用内置模板的标志
17
17
  */
18
18
  export async function getComposeFiles(env) {
@@ -29,7 +29,7 @@ export async function getComposeFiles(env) {
29
29
  }
30
30
  const files = [baseFile];
31
31
  if (env === 'production') {
32
- files.push(path.join(templateDir, 'docker-compose.prod.yml'));
32
+ // Production now uses the default file (merged config)
33
33
  }
34
34
  else if (env === 'lowmem') {
35
35
  files.push(path.join(templateDir, 'docker-compose.lowmem.yml'));
@@ -68,9 +68,6 @@ export async function runCompose(files, args, isBuiltIn = false) {
68
68
  const composeArgs = files.flatMap(f => ['-f', f]);
69
69
  if (isBuiltIn) {
70
70
  composeArgs.push('--project-directory', process.cwd());
71
- // 将 INIT_DB_PATH 设置为内置 sql 文件
72
- const templateDir = path.dirname(files[0]);
73
- process.env.INIT_DB_PATH = path.join(templateDir, 'init-db.sql');
74
71
  }
75
72
  composeArgs.push(...args);
76
73
  // 使用 stdio: 'inherit' 实时显示输出
@@ -1,2 +1,2 @@
1
1
  export declare function initEnv(): Promise<void>;
2
- export declare function checkEnv(envType: 'production' | 'lowmem' | 'basic'): Promise<void>;
2
+ export declare function checkEnv(envType: 'production' | 'lowmem'): Promise<void>;
@@ -1,4 +1,4 @@
1
- export type EnvType = 'production' | 'lowmem' | 'basic';
1
+ export type EnvType = 'production' | 'lowmem';
2
2
  export declare const EnvFlag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
3
3
  export declare function setStoredEnv(env: EnvType): Promise<void>;
4
4
  export declare function clearStoredEnv(): Promise<void>;
@@ -6,14 +6,14 @@ import path from 'node:path';
6
6
  const ENV_MARKER_FILE = '.env.lock';
7
7
  export const EnvFlag = Flags.string({
8
8
  char: 'e',
9
- description: '部署环境 (production, lowmem, basic)',
10
- options: ['production', 'lowmem', 'basic'],
9
+ description: '部署环境 (production, lowmem)',
10
+ options: ['production', 'lowmem'],
11
11
  });
12
12
  async function getStoredEnv() {
13
13
  try {
14
14
  const content = await fs.readFile(path.resolve(process.cwd(), ENV_MARKER_FILE), 'utf-8');
15
15
  const env = content.trim();
16
- if (['production', 'lowmem', 'basic'].includes(env)) {
16
+ if (['production', 'lowmem'].includes(env)) {
17
17
  return env;
18
18
  }
19
19
  }
@@ -51,9 +51,8 @@ export async function selectEnvironment(env, options = {}) {
51
51
  const selected = await select({
52
52
  message: options.prompt || '请选择运行环境:',
53
53
  choices: [
54
- { name: '标准生产环境 (2C4G+) [推荐]', value: 'production' },
55
- { name: '低配环境 (1C1G/1C2G)', value: 'lowmem' },
56
- { name: '基础环境 (仅用于测试)', value: 'basic' },
54
+ { name: '标准环境 (推荐)', value: 'production' },
55
+ { name: '低配环境 (1C1G)', value: 'lowmem' },
57
56
  { name: '❌ 取消', value: '__CANCEL__' },
58
57
  ],
59
58
  loop: true,