@dangao/bun-server 1.1.2 → 1.1.4
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.
- package/docs/api.md +602 -0
- package/docs/best-practices.md +12 -0
- package/docs/custom-decorators.md +440 -0
- package/docs/deployment.md +447 -0
- package/docs/error-handling.md +462 -0
- package/docs/extensions.md +569 -0
- package/docs/guide.md +634 -0
- package/docs/migration.md +10 -0
- package/docs/performance.md +452 -0
- package/docs/troubleshooting.md +286 -0
- package/docs/zh/api.md +168 -0
- package/docs/zh/best-practices.md +38 -0
- package/docs/zh/custom-decorators.md +466 -0
- package/docs/zh/deployment.md +445 -0
- package/docs/zh/error-handling.md +456 -0
- package/docs/zh/extensions.md +584 -0
- package/docs/zh/guide.md +361 -0
- package/docs/zh/migration.md +86 -0
- package/docs/zh/performance.md +451 -0
- package/docs/zh/troubleshooting.md +279 -0
- package/package.json +4 -3
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# Production Deployment Guide
|
|
2
|
+
|
|
3
|
+
This guide covers best practices for deploying Bun Server Framework applications
|
|
4
|
+
to production.
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
|
|
8
|
+
- [Prerequisites](#prerequisites)
|
|
9
|
+
- [Environment Setup](#environment-setup)
|
|
10
|
+
- [Configuration](#configuration)
|
|
11
|
+
- [Process Management](#process-management)
|
|
12
|
+
- [Reverse Proxy](#reverse-proxy)
|
|
13
|
+
- [Monitoring](#monitoring)
|
|
14
|
+
- [Security](#security)
|
|
15
|
+
- [Scaling](#scaling)
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- Bun runtime (latest stable version)
|
|
20
|
+
- Node.js 18+ (for compatibility)
|
|
21
|
+
- Production-ready database (PostgreSQL, MySQL, etc.)
|
|
22
|
+
- Reverse proxy (Nginx, Caddy, etc.)
|
|
23
|
+
|
|
24
|
+
## Environment Setup
|
|
25
|
+
|
|
26
|
+
### Install Bun
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# On Linux/macOS
|
|
30
|
+
curl -fsSL https://bun.sh/install | bash
|
|
31
|
+
|
|
32
|
+
# Verify installation
|
|
33
|
+
bun --version
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Set Environment Variables
|
|
37
|
+
|
|
38
|
+
Create a `.env.production` file:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
NODE_ENV=production
|
|
42
|
+
PORT=3000
|
|
43
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
|
|
44
|
+
JWT_SECRET=your-secret-key-here
|
|
45
|
+
LOG_LEVEL=info
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Load environment variables in your application:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { ConfigModule } from "@dangao/bun-server";
|
|
52
|
+
|
|
53
|
+
ConfigModule.forRoot({
|
|
54
|
+
load: (env) => ({
|
|
55
|
+
port: Number(env.PORT) || 3000,
|
|
56
|
+
database: {
|
|
57
|
+
url: env.DATABASE_URL,
|
|
58
|
+
},
|
|
59
|
+
jwt: {
|
|
60
|
+
secret: env.JWT_SECRET,
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Configuration
|
|
67
|
+
|
|
68
|
+
### Production Configuration
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { Application } from "@dangao/bun-server";
|
|
72
|
+
import { ConfigModule } from "@dangao/bun-server";
|
|
73
|
+
import { LoggerModule, LogLevel } from "@dangao/bun-server";
|
|
74
|
+
|
|
75
|
+
ConfigModule.forRoot({
|
|
76
|
+
defaultConfig: {
|
|
77
|
+
app: {
|
|
78
|
+
name: "MyApp",
|
|
79
|
+
port: Number(process.env.PORT) || 3000,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
LoggerModule.forRoot({
|
|
85
|
+
logger: {
|
|
86
|
+
level: LogLevel.INFO, // Use INFO in production
|
|
87
|
+
prefix: "App",
|
|
88
|
+
},
|
|
89
|
+
enableRequestLogging: true,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const app = new Application({
|
|
93
|
+
port: Number(process.env.PORT) || 3000,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Register modules and start
|
|
97
|
+
await app.listen();
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Error Handling
|
|
101
|
+
|
|
102
|
+
Ensure proper error handling in production:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Global error handler is enabled by default
|
|
106
|
+
// Customize error responses if needed
|
|
107
|
+
app.use(async (ctx, next) => {
|
|
108
|
+
try {
|
|
109
|
+
return await next();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// Log error
|
|
112
|
+
console.error("Request error:", error);
|
|
113
|
+
|
|
114
|
+
// Return appropriate error response
|
|
115
|
+
if (error instanceof HttpException) {
|
|
116
|
+
return ctx.createResponse(
|
|
117
|
+
{ error: error.message },
|
|
118
|
+
{ status: error.statusCode },
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Generic error
|
|
123
|
+
return ctx.createResponse(
|
|
124
|
+
{ error: "Internal Server Error" },
|
|
125
|
+
{ status: 500 },
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Process Management
|
|
132
|
+
|
|
133
|
+
### Using PM2
|
|
134
|
+
|
|
135
|
+
Install PM2:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm install -g pm2
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Create `ecosystem.config.js`:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
module.exports = {
|
|
145
|
+
apps: [{
|
|
146
|
+
name: "bun-server-app",
|
|
147
|
+
script: "bun",
|
|
148
|
+
args: "run src/index.ts",
|
|
149
|
+
instances: "max", // Use all CPU cores
|
|
150
|
+
exec_mode: "cluster",
|
|
151
|
+
env: {
|
|
152
|
+
NODE_ENV: "production",
|
|
153
|
+
PORT: 3000,
|
|
154
|
+
},
|
|
155
|
+
error_file: "./logs/error.log",
|
|
156
|
+
out_file: "./logs/out.log",
|
|
157
|
+
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
|
|
158
|
+
merge_logs: true,
|
|
159
|
+
}],
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Start with PM2:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pm2 start ecosystem.config.js
|
|
167
|
+
pm2 save
|
|
168
|
+
pm2 startup # Enable auto-start on system reboot
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Using systemd
|
|
172
|
+
|
|
173
|
+
Create `/etc/systemd/system/bun-server.service`:
|
|
174
|
+
|
|
175
|
+
```ini
|
|
176
|
+
[Unit]
|
|
177
|
+
Description=Bun Server Application
|
|
178
|
+
After=network.target
|
|
179
|
+
|
|
180
|
+
[Service]
|
|
181
|
+
Type=simple
|
|
182
|
+
User=www-data
|
|
183
|
+
WorkingDirectory=/var/www/bun-server
|
|
184
|
+
ExecStart=/usr/local/bin/bun run src/index.ts
|
|
185
|
+
Restart=always
|
|
186
|
+
RestartSec=10
|
|
187
|
+
Environment=NODE_ENV=production
|
|
188
|
+
Environment=PORT=3000
|
|
189
|
+
|
|
190
|
+
[Install]
|
|
191
|
+
WantedBy=multi-user.target
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Enable and start:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
sudo systemctl enable bun-server
|
|
198
|
+
sudo systemctl start bun-server
|
|
199
|
+
sudo systemctl status bun-server
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Reverse Proxy
|
|
203
|
+
|
|
204
|
+
### Nginx Configuration
|
|
205
|
+
|
|
206
|
+
```nginx
|
|
207
|
+
upstream bun_server {
|
|
208
|
+
server localhost:3000;
|
|
209
|
+
keepalive 64;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
server {
|
|
213
|
+
listen 80;
|
|
214
|
+
server_name example.com;
|
|
215
|
+
|
|
216
|
+
# Redirect HTTP to HTTPS
|
|
217
|
+
return 301 https://$server_name$request_uri;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
server {
|
|
221
|
+
listen 443 ssl http2;
|
|
222
|
+
server_name example.com;
|
|
223
|
+
|
|
224
|
+
ssl_certificate /path/to/cert.pem;
|
|
225
|
+
ssl_certificate_key /path/to/key.pem;
|
|
226
|
+
|
|
227
|
+
# Security headers
|
|
228
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
229
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
230
|
+
add_header X-XSS-Protection "1; mode=block" always;
|
|
231
|
+
|
|
232
|
+
# Gzip compression
|
|
233
|
+
gzip on;
|
|
234
|
+
gzip_vary on;
|
|
235
|
+
gzip_min_length 1024;
|
|
236
|
+
gzip_types text/plain text/css application/json application/javascript;
|
|
237
|
+
|
|
238
|
+
location / {
|
|
239
|
+
proxy_pass http://bun_server;
|
|
240
|
+
proxy_http_version 1.1;
|
|
241
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
242
|
+
proxy_set_header Connection 'upgrade';
|
|
243
|
+
proxy_set_header Host $host;
|
|
244
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
245
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
246
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
247
|
+
proxy_cache_bypass $http_upgrade;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Caddy Configuration
|
|
253
|
+
|
|
254
|
+
Create `Caddyfile`:
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
example.com {
|
|
258
|
+
reverse_proxy localhost:3000 {
|
|
259
|
+
header_up X-Real-IP {remote_host}
|
|
260
|
+
header_up X-Forwarded-For {remote_host}
|
|
261
|
+
header_up X-Forwarded-Proto {scheme}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Monitoring
|
|
267
|
+
|
|
268
|
+
### Health Checks
|
|
269
|
+
|
|
270
|
+
Use the built-in HealthModule:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import { HealthModule } from "@dangao/bun-server";
|
|
274
|
+
|
|
275
|
+
HealthModule.forRoot({
|
|
276
|
+
indicators: [
|
|
277
|
+
{
|
|
278
|
+
name: "database",
|
|
279
|
+
check: async () => {
|
|
280
|
+
// Check database connection
|
|
281
|
+
await db.query("SELECT 1");
|
|
282
|
+
return { status: "up" };
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Health endpoints:
|
|
289
|
+
// GET /health - Overall health
|
|
290
|
+
// GET /ready - Readiness check
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Logging
|
|
294
|
+
|
|
295
|
+
Configure structured logging:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
LoggerModule.forRoot({
|
|
299
|
+
logger: {
|
|
300
|
+
level: LogLevel.INFO,
|
|
301
|
+
format: "json", // Use JSON in production
|
|
302
|
+
},
|
|
303
|
+
enableRequestLogging: true,
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Metrics
|
|
308
|
+
|
|
309
|
+
Use MetricsModule for application metrics:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { MetricsModule } from "@dangao/bun-server";
|
|
313
|
+
|
|
314
|
+
MetricsModule.forRoot({
|
|
315
|
+
enableDefaultMetrics: true,
|
|
316
|
+
enableHttpMetrics: true,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Metrics endpoint: GET /metrics
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Security
|
|
323
|
+
|
|
324
|
+
### HTTPS
|
|
325
|
+
|
|
326
|
+
Always use HTTPS in production. Configure SSL/TLS certificates (Let's Encrypt,
|
|
327
|
+
etc.).
|
|
328
|
+
|
|
329
|
+
### Security Headers
|
|
330
|
+
|
|
331
|
+
Add security middleware:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
app.use(async (ctx, next) => {
|
|
335
|
+
const response = await next();
|
|
336
|
+
response.headers.set("X-Frame-Options", "SAMEORIGIN");
|
|
337
|
+
response.headers.set("X-Content-Type-Options", "nosniff");
|
|
338
|
+
response.headers.set("X-XSS-Protection", "1; mode=block");
|
|
339
|
+
response.headers.set("Strict-Transport-Security", "max-age=31536000");
|
|
340
|
+
return response;
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Rate Limiting
|
|
345
|
+
|
|
346
|
+
Enable rate limiting:
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { createRateLimitMiddleware } from "@dangao/bun-server";
|
|
350
|
+
|
|
351
|
+
app.use(createRateLimitMiddleware({
|
|
352
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
353
|
+
max: 100, // Limit each IP to 100 requests per windowMs
|
|
354
|
+
}));
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Input Validation
|
|
358
|
+
|
|
359
|
+
Always validate input:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import { Validate, IsString, IsEmail } from '@dangao/bun-server';
|
|
363
|
+
|
|
364
|
+
class CreateUserDto {
|
|
365
|
+
@IsString()
|
|
366
|
+
public name!: string;
|
|
367
|
+
|
|
368
|
+
@IsEmail()
|
|
369
|
+
public email!: string;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
@POST('/users')
|
|
373
|
+
public createUser(@Body() @Validate() user: CreateUserDto) {
|
|
374
|
+
// User is validated
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Scaling
|
|
379
|
+
|
|
380
|
+
### Horizontal Scaling
|
|
381
|
+
|
|
382
|
+
Run multiple instances behind a load balancer:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
# Start multiple instances
|
|
386
|
+
PORT=3000 bun run src/index.ts &
|
|
387
|
+
PORT=3001 bun run src/index.ts &
|
|
388
|
+
PORT=3002 bun run src/index.ts &
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Configure load balancer (Nginx, HAProxy, etc.) to distribute traffic.
|
|
392
|
+
|
|
393
|
+
### Database Connection Pooling
|
|
394
|
+
|
|
395
|
+
Configure connection pooling:
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
DatabaseModule.forRoot({
|
|
399
|
+
database: {
|
|
400
|
+
type: "postgres",
|
|
401
|
+
config: {
|
|
402
|
+
connectionString: process.env.DATABASE_URL,
|
|
403
|
+
max: 20, // Maximum pool size
|
|
404
|
+
min: 5, // Minimum pool size
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Caching
|
|
411
|
+
|
|
412
|
+
Use CacheModule for frequently accessed data:
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
CacheModule.forRoot({
|
|
416
|
+
store: new RedisCacheStore(redisClient),
|
|
417
|
+
defaultTtl: 3600000, // 1 hour
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Session Storage
|
|
422
|
+
|
|
423
|
+
Use Redis for distributed session storage:
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
SessionModule.forRoot({
|
|
427
|
+
store: new RedisSessionStore(redisClient),
|
|
428
|
+
maxAge: 86400000, // 24 hours
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Checklist
|
|
433
|
+
|
|
434
|
+
Before deploying to production:
|
|
435
|
+
|
|
436
|
+
- [ ] Environment variables configured
|
|
437
|
+
- [ ] HTTPS enabled
|
|
438
|
+
- [ ] Error handling configured
|
|
439
|
+
- [ ] Logging configured
|
|
440
|
+
- [ ] Health checks enabled
|
|
441
|
+
- [ ] Rate limiting enabled
|
|
442
|
+
- [ ] Security headers set
|
|
443
|
+
- [ ] Database connection pooling configured
|
|
444
|
+
- [ ] Process manager configured (PM2/systemd)
|
|
445
|
+
- [ ] Reverse proxy configured
|
|
446
|
+
- [ ] Monitoring set up
|
|
447
|
+
- [ ] Backup strategy in place
|