-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path.env.example
More file actions
363 lines (295 loc) · 18.1 KB
/
Copy path.env.example
File metadata and controls
363 lines (295 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# =============================================================================
# nest-server — Environment Variables
# =============================================================================
# Copy to `.env` and adjust values.
#
# Legend:
# - Uncommented lines → REQUIRED for a production deployment.
# - Commented lines → OPTIONAL (defaults apply, or feature is off).
#
# Local/dev/ci/e2e environments have sensible fallbacks in `src/config.env.ts`
# (well-known test secrets, Mailhog defaults, localhost URLs) — you typically
# do NOT need any `.env` at all for local work.
#
# Two ways to configure:
# 1. Standard env vars → read via `process.env.X` in `src/config.env.ts`
# 2. NSC__ prefix → auto-mapped to config paths
# NSC__MONGOOSE__URI → config.mongoose.uri
# NSC__APP_URL → config.appUrl
# NSC__BASE_URL → config.baseUrl (single underscore → camelCase)
# =============================================================================
# Database (required in production)
# =============================================================================
MONGODB_URI=mongodb://localhost:27017/my-app-production
# =============================================================================
# URLs (required in production)
# =============================================================================
# API base URL — used for CORS, Passkey RP ID, email links, OAuth callbacks.
# The frontend/app URL is auto-derived: api.example.com → example.com
BASE_URL=https://api.example.com
# Frontend/app URL (optional — auto-derived from BASE_URL if unset)
# NSC__APP_URL=https://example.com
# =============================================================================
# Authentication Secrets (required in production)
# =============================================================================
# Better-Auth secret — signs session cookies + JWTs. Minimum 32 characters.
# Generate with:
# node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
BETTER_AUTH_SECRET=CHANGE_ME_generate_32plus_chars_with_node_crypto_randomBytes
# JWT secrets (optional — only required when using Legacy Auth endpoints).
# With BetterAuth-only mode, these can stay unset.
# Generate with:
# node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"
# JWT_SECRET=CHANGE_ME_generate_64plus_chars_with_node_crypto_randomBytes
# JWT_REFRESH_SECRET=CHANGE_ME_different_64plus_chars_than_JWT_SECRET
# =============================================================================
# Email — SMTP required in production, Brevo optional overlay
# =============================================================================
# -----------------------------------------------------------------------------
# SMTP (required — baseline transport for ALL outgoing mail)
# -----------------------------------------------------------------------------
# Any SMTP provider: AWS SES, SendGrid, Postmark, Mailgun, self-hosted Postfix.
# Handles all auth flows and custom app emails.
EMAIL_DEFAULT_SENDER=noreply@example.com
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=smtp-user
SMTP_PASS=smtp-password
# EMAIL_DEFAULT_SENDER_NAME=My App # default: "Nest Server"
# SMTP_SECURE=true # default: true (set false for STARTTLS on :587)
# -----------------------------------------------------------------------------
# Auth-link logging (development convenience)
# -----------------------------------------------------------------------------
# Outside production-like environments the server prints the verification and
# password-reset links to stdout so you can follow them without a mail server.
# The address is masked; the URL is not — it carries a bearer token, and a reset
# link is a full account takeover. Never enable this where real accounts live:
# it is already suppressed for `env: production` / `env: staging` and for
# NODE_ENV=production. Set to 0 to suppress it everywhere else too.
# LT_LOG_AUTH_URLS=0
# -----------------------------------------------------------------------------
# Brevo Transactional API (optional overlay for template-based mails)
# -----------------------------------------------------------------------------
# Brevo (ex-Sendinblue) sends via HTTPS with server-side templates.
# Runs IN PARALLEL to SMTP — only used when a module references a template id
# (`betterAuth.emailVerification.brevoTemplateId` for the verification mail,
# `betterAuth.emailVerification.passwordResetBrevoTemplateId` for the password-reset
# mail — they are separate on purpose, and the reset one does NOT fall back to the
# verification one). All other mails still flow through the SMTP transport above.
# Get an API key at https://app.brevo.com/settings/keys/api
# BREVO_API_KEY=xkeysib-your-brevo-api-key
# Only for the manual smoke script (scripts/brevo-smoke.ts, framework repo only).
# It sends REAL mail on REAL quota — see docs/brevo-manual-test.md.
# BREVO_SMOKE_TO=you@your-mailbox.tld
# BREVO_SMOKE_TEMPLATE_ID=12 # optional, additionally exercises sendMail()
# =============================================================================
# CORS (optional — origins auto-derived from BASE_URL + APP_URL)
# =============================================================================
# Additional allowed origins (comma-separated, merged with APP_URL + BASE_URL).
# CORS_ALLOWED_ORIGINS=https://admin.example.com,https://partner.example.com
# =============================================================================
# Feature Toggles (optional — sensible defaults apply)
# =============================================================================
# Disable Legacy Auth endpoints after all users have migrated to BetterAuth (IAM).
# Default: true (legacy endpoints active). Set to 'false' to return HTTP 410 Gone.
# LEGACY_AUTH_ENABLED=false
# BetterAuth rate limiting (in-memory, per IP).
# Defaults: enabled=true, max=10 requests per 60s window.
# RATE_LIMIT_ENABLED=true
# RATE_LIMIT_MAX=10
# Two-Factor Authentication app name — shown in Authenticator apps (TOTP issuer).
# Default: "Nest Server"
# TWO_FACTOR_APP_NAME=My App
# =============================================================================
# Social Login (optional — BetterAuth OAuth providers)
# =============================================================================
# SOCIAL_GOOGLE_CLIENT_ID=
# SOCIAL_GOOGLE_CLIENT_SECRET=
# SOCIAL_GITHUB_CLIENT_ID=
# SOCIAL_GITHUB_CLIENT_SECRET=
# =============================================================================
# AI Assistant module (optional — enabled when an `ai` config block is present)
# =============================================================================
# Connections to LLMs are managed at runtime (admin CRUD) and stored in the DB
# with AES-256-GCM-encrypted API keys. The variables below only (a) seed ONE
# default connection on first start and (b) provide the encryption secret.
# Encryption secret for stored API keys — REQUIRED in production when AI is used.
# Without it, keys are encrypted with an insecure development default (warned only).
# Minimum 32 characters. Generate with:
# node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# NSC__AI__ENCRYPTION_SECRET=CHANGE_ME_generate_32plus_chars_with_node_crypto_randomBytes
# One-time seed of a default connection (only seeded when AI_BASE_URL is set).
# Works with any OpenAI-compatible endpoint (local runtime or hosted).
# AI_BASE_URL=https://llm.example.com/v1
# AI_API_KEY=your-llm-api-key
# AI_MODEL=gpt-oss-120b
# AI_SUPPORTS_JSON=true # backend supports response_format json_object
# AI_SUPPORTS_NATIVE_TOOLS=true # backend supports native function/tool calling
# MCP server OAuth 2.1 secret (only when ai.mcp.oauth is enabled). Minimum 32 chars.
# NSC__AI__MCP__OAUTH_SECRET=CHANGE_ME_generate_32plus_chars_with_node_crypto_randomBytes
# =============================================================================
# Hub — admin area / operator cockpit (optional)
# =============================================================================
# Build-free, ADMIN-gated dashboard at /hub (runtime info + admin tools). NEVER
# enabled implicitly — it must be switched on per environment. Prefer configuring
# it in config.env.ts; the NSC__HUB__* variables below are the env-var equivalent.
#
# Enable at the default path (/hub), admin-only:
# NSC__HUB=true
#
# Or configure explicitly:
# NSC__HUB__PATH=hub # base path (default 'hub')
# NSC__HUB__COLLECTORS__QUERIES=true # opt-in query profiler (enables driver command monitoring)
# NSC__HUB__MAILBOX__MODE=capture # built-in Mailpit-style mail capture (dev/test only!)
#
# WARNING: mailbox mode 'capture' intercepts and DOES NOT SEND mail. It throws at
# startup in production/staging. Use 'copy' (send + record) if you need it there.
# Do NOT set NSC__HUB in production unless you intend the cockpit reachable there.
# =============================================================================
# File storage — S3 / S3-compatible (optional, since 11.33)
# =============================================================================
# Files are served S3 → filesystem → GridFS, so switching is incremental: a file
# is read from S3 as soon as its `s3-files` metadata document exists, everything
# else keeps coming from where it is. No big-bang migration, no downtime window.
#
# WARNING — `NSC__S3__BUCKET` alone flips the storage driver. It makes S3 the
# DERIVED default for `file.storage`, and the server then asserts the driver is
# usable at boot. An app whose FileService still pins GridFS (`super(connection,
# 'fs')`) stops with:
# "File storage 's3' was selected automatically (s3.bucket is configured) but
# is not available."
# Do not configure S3 for a deployment before its code is ready for it.
#
# WARNING — NSC__ values are NOT parsed as JSON, but 'true'/'false' become
# booleans and anything numeric becomes a NUMBER. An all-digit secret therefore
# arrives as a number and the signature fails. Prefer keys with letters.
# NSC__S3__BUCKET=my-app-files
# NSC__S3__REGION=eu-central-1 # default 'us-east-1'
# Credentials — omit both to use the AWS SDK default chain (env, instance
# profile, IRSA, ...). Set them for S3-compatible providers.
# CAUTION: an empty NSC__ value is not "unset" — it becomes the NUMBER 0, because
# the loader coerces anything numeric and Number('') is 0. Uncommenting these with
# no value therefore sets accessKeyId to 0 rather than omitting it, which defeats
# the credential chain below and fails with an opaque auth error. To omit a key,
# leave its line COMMENTED OUT.
# NSC__S3__ACCESS_KEY_ID=AKIAEXAMPLE
# NSC__S3__SECRET_ACCESS_KEY=your-secret-access-key
# S3-compatible services (MinIO, RustFS, STACKIT, Ceph) — omit for AWS S3.
# Path-style addressing is required by most of them.
# NSC__S3__ENDPOINT=https://object.storage.example.com
# NSC__S3__FORCE_PATH_STYLE=true # default false
# Resumable TUS uploads are staged here before the finished object is moved into
# `bucket`. Defaults to `bucket` — set it only if you want them separated.
# NSC__S3__STAGING_BUCKET=my-app-uploads-staging
# Create missing buckets at startup. Off by default: production buckets come
# from infrastructure code, and their credentials usually cannot CreateBucket.
# Either way the server verifies the buckets at boot and logs an actionable
# error instead of failing the first upload with an opaque 500.
# NSC__S3__AUTO_CREATE_BUCKET=true # default false
# Serve downloads as presigned redirects instead of streaming through the API.
# The URL is a session-less BEARER CAPABILITY: once issued, anyone holding the
# string can download until it expires — there is no revocation short of
# deleting the object or rotating the credentials.
# Do NOT set both of these. The NSC__ path builder walks segments and assigns
# `current[segment] = current[segment] || {}`, so the scalar and the nested key
# COLLIDE: with the scalar processed first the result is {presignedDownloads: true}
# and the expiry is SILENTLY DROPPED — measured, not theorised. Everyone who sets
# 60 and everyone who sets 86400 then gets the default 300, with no error, for a
# capability that cannot be revoked. In the other processing order it is worse: the
# nested assignment throws a raw TypeError and the boot fails.
#
# Set the nested key ALONE — its presence enables the feature:
# NSC__S3__PRESIGNED_DOWNLOADS__EXPIRES_IN_SECONDS=300 # default 300
#
# Or use the JSON channel, which has no such collision:
# NEST_SERVER_CONFIG='{"s3":{"presignedDownloads":{"expiresInSeconds":300}}}'
# Pin the driver explicitly instead of relying on the derived default.
# NSC__FILE__STORAGE=s3 # 'filesystem' | 'gridfs' | 's3'
# =============================================================================
# Redis — shared state for multiple replicas (optional, since 11.33)
# =============================================================================
# Used by every distributed feature: rate limiting, cron deduplication, GraphQL
# subscriptions, caches and Hub collectors. Without it each replica keeps its own
# state — rate limits count per instance and a cron job runs once PER REPLICA.
# Presence implies enabled.
# NSC__REDIS__HOST=redis
# NSC__REDIS__PORT=6379
# NSC__REDIS__DB=0
# Same caution as the S3 credentials above: an empty value becomes the number 0,
# so an uncommented-but-empty line sends 0 as the password. Omit by commenting out.
# NSC__REDIS__USERNAME=default
# NSC__REDIS__PASSWORD=your-redis-password
# NSC__REDIS__KEY_PREFIX=my-app # default: the package name
# Or as a single URL instead of the fields above:
# NSC__REDIS__URL=redis://user:pass@redis:6379/0
# NSC__REDIS__ENABLED=false # pre-configure without switching on
# =============================================================================
# Reverse proxy — required behind a load balancer / ingress
# =============================================================================
# Express `trust proxy`: how far up the `X-Forwarded-For` chain the app believes.
# This is what makes `request.ip` correct, and EVERY IP-keyed rate limit depends
# on it. Left unset behind a proxy, every request appears to come from the proxy,
# so all clients share ONE rate-limit bucket — one noisy client throttles all of
# them, and a per-IP limit protects nothing.
#
# Number = how many proxy hops to trust (1 for a single ingress).
# NSC__TRUST_PROXY=1
# =============================================================================
# Input validation (since 11.16)
# =============================================================================
# Input properties NOT decorated with `@UnifiedField` are SILENTLY STRIPPED by
# default. A plain `@Field` property on an input class never reaches the service:
# no error, no warning, the value is simply gone — a sign-up carrying firstName
# and lastName arrives with only email and password.
#
# 'strip' (default) — remove them silently
# 'error' — throw BadRequestException (LTNS_0303); use while porting
# false — pre-11.16 behaviour, nothing is stripped
#
# Set `false` when migrating a large legacy input surface, and port the classes
# to `@UnifiedField` afterwards.
# NSC__SECURITY__MAP_AND_VALIDATE_PIPE__NON_WHITELISTED_FIELDS=error
# =============================================================================
# Graceful shutdown (optional, since 11.33)
# =============================================================================
# Delay between receiving the shutdown signal and starting the Nest shutdown
# sequence. Gives the load balancer time to deregister the instance before
# in-flight connections are drained — required for zero-downtime rollouts.
# NSC__SHUTDOWN_DELAY_MS=5000
# =============================================================================
# Multi-tenancy (optional)
# =============================================================================
# Tenant isolation with membership validation. The active tenant comes from a
# request header (default `x-tenant-id`), and queries are scoped by a mongoose
# plugin. Turning this on changes what every query returns — verify against a
# copy of the data first.
# NSC__MULTI_TENANCY__ENABLED=true
# NSC__MULTI_TENANCY__HEADER_NAME=x-tenant-id
# NSC__MULTI_TENANCY__MEMBERSHIP_MODEL=TenantMember
# NSC__MULTI_TENANCY__ADMIN_BYPASS=true # platform admins see every tenant
# NSC__MULTI_TENANCY__CACHE_TTL_MS=60000
# =============================================================================
# TUS resumable uploads (enabled by default)
# =============================================================================
# TUS is ON without any configuration. Since 11.33 it requires a session:
# `tus.roles` defaults to `['s_user']`, not `s_everyone` — an anonymous upload
# now answers 401 where it used to succeed.
# NSC__TUS__ENABLED=false # switch it off entirely
# NSC__TUS__PATH=/tus # default '/tus' — used VERBATIM, keep the leading slash
# NSC__TUS__UPLOAD_DIR=./uploads-tus # default 'uploads/tus'
# =============================================================================
# Initial Admin (optional — first deployment only; remove after setup)
# =============================================================================
# Creates a single admin user on first startup if the user collection is empty.
# NSC__SYSTEM_SETUP__INITIAL_ADMIN__EMAIL=admin@example.com
# NSC__SYSTEM_SETUP__INITIAL_ADMIN__PASSWORD=YourSecurePassword123!
# NSC__SYSTEM_SETUP__INITIAL_ADMIN__NAME=Admin
# =============================================================================
# Migrations (optional)
# =============================================================================
# Strict integrity mode: fail `migrate up`/`list` when a migration recorded in the
# state store has no file on disk (default: tolerate with a warning, so deleting
# old, git-tracked migration files never blocks boot). Recommended `true` for
# immutable production images — a missing file there means a broken build or a
# state-store mismatch. Accepts 1|true|yes (case-insensitive).
# NSC__MIGRATE__STRICT=true