-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
503 lines (420 loc) · 21 KB
/
Copy path.env.example
File metadata and controls
503 lines (420 loc) · 21 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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
# Copy to .env and fill in. .env is gitignored; this file is not, so never
# put a real secret here.
#
# Every variable below is one the code actually reads. Anything not listed is
# not consulted.
# ---------------------------------------------------------------------------
# Core
# ---------------------------------------------------------------------------
# development | production | testing
DJANGO_ENVIRONMENT=development
# Required outside development -- the app refuses to start without it.
# Generate one with:
# python -c "from django.core.management.utils import get_random_secret_key as k; print(k())"
SECRET_KEY=
# Comma-separated. Required in production.
ALLOWED_HOSTS=localhost,127.0.0.1
# Where the SPA is served from -- the browser origin, not the API's.
#
# MUST include the scheme, and MUST NOT end in a slash. Both are checked by
# `manage.py check`, but neither error names this variable: no scheme gives you
# corsheaders.E013 and 4_0.E001, a trailing slash gives you corsheaders.E014.
# A trailing slash also puts a `//` into every password reset link, and nothing
# reports that at all.
#
# https://example.com yes
# example.com no scheme
# https://example.com/ trailing slash
#
# Feeds CORS_ALLOWED_ORIGINS, CSRF_TRUSTED_ORIGINS, the links in reset,
# verification and invitation emails, the Stripe return URLs and the social
# login redirects. See docs/getting-started.md.
FRONTEND_URL=http://localhost:3000
# ---------------------------------------------------------------------------
# Database
# ---------------------------------------------------------------------------
# Managed hosts (Railway, Render, Heroku, Fly) hand you a single DATABASE_URL.
# When it is set it wins, and the DB_* variables below are ignored.
#
# postgres://USER:PASSWORD@HOST:PORT/DATABASE
#
# postgresql:// works too. The port is required. Percent-encode a password
# containing @ / : or #, or the URL parses into something silently wrong.
#
# ON RAILWAY: adding the Postgres service does NOT inject this. Reference it
# explicitly in the web service's variables as ${{Postgres.DATABASE_URL}} --
# the dashboard shows a healthy database either way.
#
# Prefer this over the DB_* variables in production: a remote host configured
# through DATABASE_URL gets sslmode=require automatically, and the same host
# through DB_* does not.
# DATABASE_URL=postgres://user:password@host:5432/dbname
# The DB_* variables below are for local development and docker compose. On a
# managed host use DATABASE_URL instead -- setting DB_HOST there leaves DB_NAME
# and DB_PASSWORD at defaults the provider never created, and production
# refuses to start rather than retry a connection that cannot succeed.
DB_NAME=app
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=localhost
DB_PORT=5432
# TLS to the database. Defaults on for a remote DATABASE_URL, off for a
# local or docker-compose one. This setting is what decides it -- an
# ?sslmode=... query parameter on the URL is passed over and has no effect.
# DB_SSL_REQUIRE=true
# Seconds to keep a connection open. 0 disables persistent connections.
DB_CONN_MAX_AGE=60
# Port Postgres is published on by docker compose.
DB_EXPOSED_PORT=5432
# ---------------------------------------------------------------------------
# Redis (cache, Celery broker and results)
# ---------------------------------------------------------------------------
REDIS_URL=redis://localhost:6379
# Default to REDIS_URL/0; override only if broker and cache live apart.
# CELERY_BROKER_URL=
# CELERY_RESULT_BACKEND=
# ---------------------------------------------------------------------------
# Email
#
# Development defaults to the console backend, which prints messages to the
# terminal. Point EMAIL_BACKEND at django_ses.SESBackend to send for real.
# ---------------------------------------------------------------------------
# EMAIL_BACKEND=django_ses.SESBackend
DEFAULT_FROM_EMAIL=no-reply@example.com
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_SES_REGION_NAME=us-east-1
# Hand rendered messages to Celery instead of sending them in the request.
# Needs a worker running (`celery -A template worker`); off by default because
# the default compose stack has none, and a queued message nobody drains is
# worse than a slow one. Templates render inline either way.
# EMAIL_ASYNC=false
# ---------------------------------------------------------------------------
# Organizations (teams)
#
# The B2B shape: users belong to organizations, invitations, per-org roles and
# seat limits. Off by default -- the single-user shape costs nothing. Nothing
# outside apps/organizations references it, so it also deletes cleanly.
# ---------------------------------------------------------------------------
# ORGANIZATIONS_ENABLED=false
# How long an invitation stays redeemable.
# INVITATION_EXPIRY_DAYS=7
# ---------------------------------------------------------------------------
# API keys
#
# Long-lived credentials for CLIs, CI jobs and server-to-server calls, which
# session cookies cannot serve. The key is shown once at creation and only a
# digest is stored, so it is not recoverable afterwards by anyone.
# ---------------------------------------------------------------------------
# API_KEYS_ENABLED=false
# Machine traffic gets its own throttle budget, separate from THROTTLE_USER.
# THROTTLE_API_KEY=10000/day
# ---------------------------------------------------------------------------
# Audit log
#
# An append-only record of security-relevant actions. Nothing expires on its
# own -- schedule `manage.py prune_audit_log` if the table's growth matters.
# ---------------------------------------------------------------------------
# AUDIT_LOG_ENABLED=false
# AUDIT_LOG_RETENTION_DAYS=365
# ---------------------------------------------------------------------------
# Two-factor authentication (TOTP)
# ---------------------------------------------------------------------------
# TWO_FACTOR_ENABLED=false
# Seconds a half-finished login stays verifiable.
# TWO_FACTOR_PENDING_TIMEOUT=300
# Encrypts TOTP secrets at rest. Falls back to SECRET_KEY -- but rotating
# SECRET_KEY would then lock every enrolled user out of their own account,
# so set this separately if you will ever rotate.
# TWO_FACTOR_SECRET_KEY=
# ---------------------------------------------------------------------------
# File uploads
#
# The default filesystem backend is a DEVELOPMENT CONVENIENCE ONLY. Container
# filesystems are ephemeral, so on any managed host every uploaded file
# disappears on the next deploy, silently, leaving rows pointing at nothing.
# Setting AWS_STORAGE_BUCKET_NAME swaps in S3, which is what a deployment
# needs. The bucket stays private and URLs are signed.
# ---------------------------------------------------------------------------
# UPLOADS_ENABLED=false
# AWS_STORAGE_BUCKET_NAME=
# Falls back to AWS_SES_REGION_NAME, then us-east-1.
# AWS_S3_REGION_NAME=
# For S3-compatible storage (MinIO, R2, Spaces).
# AWS_S3_ENDPOINT_URL=
# Sniffed from the file's own bytes -- never the header or the extension.
# UPLOAD_ALLOWED_TYPES=image/jpeg,image/png,image/gif,image/webp,application/pdf
# UPLOAD_MAX_BYTES=5242880
# How long a signed download URL stays usable.
# UPLOAD_URL_EXPIRY_SECONDS=300
# ---------------------------------------------------------------------------
# MCP server
#
# Exposes the application's own capabilities as MCP tools, so an agent can act
# on behalf of whoever's credential it sends. Off by default: making an
# application agent-callable is a decision to take deliberately.
#
# The endpoint is mounted beside Django rather than inside its URLconf, because
# the transport is ASGI-only. Serving is already ASGI, so nothing else changes.
# ---------------------------------------------------------------------------
# MCP_SERVER_ENABLED=false
# What a client shows in its list of connected servers. Defaults to API_TITLE.
# MCP_SERVER_NAME=
# Where the endpoint is mounted. Changing it means reconfiguring every
# connected client.
# MCP_MOUNT_PATH=/mcp
# ---------------------------------------------------------------------------
# MCP OAuth -- resource server only
#
# Validates OAuth 2.1 access tokens. It never issues them. Everything
# genuinely dangerous -- authorize, consent, code exchange, PKCE, redirect-URI
# matching, token signing, key rotation -- belongs to the authorization server,
# which is not this application. RFC 9728 formalises the split.
#
# Independent of MCP_SERVER_ENABLED. The MCP endpoint forwards whatever
# Authorization header it is given, so it works on API keys alone; and bearer
# tokens are useful to the REST API whether or not MCP is on.
#
# Turning this on requires an authorization server to point at, so there is
# nothing sensible to default to and the app refuses to boot without one.
# ---------------------------------------------------------------------------
# MCP_OAUTH_ENABLED=false
# The authorization server's identifier, matched against a token's `iss`
# exactly. Required when the flag is on.
# MCP_OAUTH_ISSUER=https://auth.example.com/
# This resource server's own identifier, matched against a token's `aud`
# exactly. Required when the flag is on -- and the check that matters most: a
# token minted for a different resource must be refused, or this application
# becomes a confused deputy for every service sharing the issuer.
# MCP_OAUTH_AUDIENCE=https://app.example.com/mcp
# Where the signing keys are published. Defaults to the conventional path
# under the issuer, which is what every compliant server uses.
# MCP_OAUTH_JWKS_URL=
# How long a fetched key set is trusted. Bounded so a rotation is picked up
# without a restart, and so a poisoned cache cannot persist.
# MCP_OAUTH_JWKS_CACHE_SECONDS=300
# The claim carrying the Django user's identifier, and the field to look it up
# by. The authorization server delegates login here, so `sub` is whatever the
# consent step put there -- the primary key by default. A token for an unknown
# subject is refused, never used to create an account.
# MCP_OAUTH_SUBJECT_CLAIM=sub
# MCP_OAUTH_USER_LOOKUP_FIELD=pk
# The scope an unsafe method requires. Mirrors the API-key read/write split: a
# token without it is read-only, which is the safe default for a credential
# handed to an agent. Set empty to let any valid token write.
# MCP_OAUTH_WRITE_SCOPE=mcp:write
# Scopes advertised in the protected-resource metadata document, so a client
# knows what to ask the authorization server for.
# MCP_OAUTH_SCOPES_SUPPORTED=mcp:read,mcp:write
# ---------------------------------------------------------------------------
# MCP client -- calling out to other servers
#
# The mirror of MCP_SERVER_ENABLED, and independent of it: an application can
# be agent-callable without itself being an agent, and the other way round.
#
# Which servers exist is decided by the modules under
# apps/mcp_client/servers/, in the repository and reviewable in a diff. The
# settings below choose which of those are live and how the call is made; they
# cannot introduce a server nobody wrote a file for.
# ---------------------------------------------------------------------------
# MCP_CLIENT_ENABLED=false
# Slugs to enable, comma-separated. Empty means every server defined under
# servers/. A slug with no module raises at startup rather than being silently
# ignored -- a typo would otherwise just make one feature quietly do nothing.
# MCP_CLIENT_SERVERS=
# The model outbound calls use. No default: a model ID baked into a template
# ages quietly, since it keeps working while better models ship and nothing
# fails to make anyone notice. Set it to a current ID -- see
# https://docs.claude.com/en/docs/about-claude/models for the list.
# MCP_CLIENT_MODEL=
# Where Claude is being called: anthropic | aws | bedrock | vertex.
# The MCP connector is available on the Claude API and Claude Platform on AWS
# only. Bedrock and Vertex route to Claude but not through the endpoint that
# fetches an MCP server, so a server needs transport='local' there.
# MCP_CLIENT_PROVIDER=anthropic
# MCP_CLIENT_MAX_TOKENS=4096
# MCP_CLIENT_TIMEOUT_SECONDS=60
# How many times the local transport hands a tool result back to the model
# before giving up. Only the local transport runs that loop -- with the
# connector, Anthropic does. Without a bound, a model that keeps asking for
# tools loops until the process is killed.
# MCP_CLIENT_MAX_TOOL_ROUNDS=8
# Encrypts a stored per-user credential at rest. Falls back to SECRET_KEY --
# rotating that makes every stored credential undecryptable and every
# connection has to be re-authorised.
# MCP_CLIENT_SECRET_KEY=
# The key outbound calls are made with. The Anthropic SDK would read this from
# the environment by itself; apps/mcp_client/clients/base.py reads it
# explicitly anyway, so that it appears in this file at all -- a variable only
# a dependency reads is invisible to the tests that keep this list honest.
# ANTHROPIC_API_KEY=
# How long password reset and verification links stay valid, in seconds.
PASSWORD_RESET_TIMEOUT=259200
# ---------------------------------------------------------------------------
# Error tracking
#
# Setting SENTRY_DSN is the only thing that turns this on -- there is no
# separate flag, and nothing is imported without it. Never armed during a test
# run, so a DSN in a CI environment cannot fill a real project with noise.
# ---------------------------------------------------------------------------
# SENTRY_DSN=
# Tags tracebacks with a commit rather than just "production". Railway and
# Render supply their own; set this only if neither applies.
# SENTRY_RELEASE=
# Off on purpose: turning it on ships email addresses, usernames and IP
# addresses to a third party.
# SENTRY_SEND_PII=false
# Performance sampling, 0.0 to 1.0. Costs quota, so opt in deliberately.
# SENTRY_TRACES_SAMPLE_RATE=0.0
# ---------------------------------------------------------------------------
# Cookies, CORS and CSRF
#
# Development leaves these alone: the Vite dev server proxies /api to Django,
# so the SPA and API are same-origin and Lax cookies work. Set them when the
# frontend is served from a different origin than the API.
# ---------------------------------------------------------------------------
# CORS_ALLOWED_ORIGINS=https://app.example.com
# CSRF_TRUSTED_ORIGINS=https://app.example.com
# SameSite=None requires Secure=true in every current browser.
# SESSION_COOKIE_SAMESITE=Lax
# CSRF_COOKIE_SAMESITE=Lax
# SESSION_COOKIE_SECURE=true
# CSRF_COOKIE_SECURE=true
# ---------------------------------------------------------------------------
# Production hardening (production settings only)
# ---------------------------------------------------------------------------
# Set false only if the app terminates TLS itself rather than sitting behind
# a proxy that sets X-Forwarded-Proto.
# USE_X_FORWARDED_PROTO=true
# SECURE_SSL_REDIRECT=true
# SECURE_HSTS_SECONDS=31536000
# SECURE_HSTS_INCLUDE_SUBDOMAINS=true
# SECURE_HSTS_PRELOAD=true
# ---------------------------------------------------------------------------
# Rate limiting
# ---------------------------------------------------------------------------
# THROTTLE_ANON=100/day
# THROTTLE_USER=1000/day
# THROTTLE_LOGIN=10/min
# THROTTLE_PASSWORD_RESET=5/hour
# Building an export walks every table the user touches and sends mail.
# THROTTLE_DATA_EXPORT=3/day
# The mobile version gate. Every installation calls it on launch and on
# foreground, and anonymous throttling is keyed by IP -- so this needs room
# for a whole office behind one address. The view answers from a one-minute
# cache, so a generous ceiling is cheap.
# THROTTLE_APP_UPGRADE=600/hour
# How long a data-export download link stays usable, in seconds.
# GDPR_EXPORT_LINK_TIMEOUT=86400
# ---------------------------------------------------------------------------
# Billing (optional -- see "Removing billing" in the README)
# ---------------------------------------------------------------------------
STRIPE_ENABLED=false
STRIPE_SECRET_KEY=
STRIPE_PUBLISHABLE_KEY=
STRIPE_WEBHOOK_SECRET=
# STRIPE_SUCCESS_URL=http://localhost:3000/subscription/success
# STRIPE_CANCEL_URL=http://localhost:3000/subscription/cancel
# Days a lapsed subscription keeps working before access is cut off.
SUBSCRIPTION_GRACE_PERIOD_DAYS=14
# ---------------------------------------------------------------------------
# Social login (optional)
# ---------------------------------------------------------------------------
# Providers are offered to the frontend only when their key is configured,
# so a button never appears for one that would fail on the redirect.
#
# The default python-social-auth pipeline hands a social identity any
# existing account with the same email. That is disabled here -- see the
# README -- because it is an account-takeover path.
SOCIAL_AUTH_ENABLED=false
GOOGLE_OAUTH2_KEY=
GOOGLE_OAUTH2_SECRET=
LINKEDIN_OAUTH2_KEY=
LINKEDIN_OAUTH2_SECRET=
# ---------------------------------------------------------------------------
# API documentation
# ---------------------------------------------------------------------------
API_TITLE=DRF Starter API
API_DESCRIPTION=API for the DRF Starter template
# ---------------------------------------------------------------------------
# Serving
# ---------------------------------------------------------------------------
# The port gunicorn binds to. Managed hosts inject this themselves.
# PORT=8000
# WEB_CONCURRENCY=3
# Whether Django serves the built SPA from website/dist. Defaults to whether
# that build exists -- on in the container, off locally where the Vite dev
# server serves it instead. Set explicitly to override.
# SERVE_SPA=true
# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------
LOG_LEVEL=INFO
# DJANGO_LOG_LEVEL=INFO
# ---------------------------------------------------------------------------
# Local development conveniences
# ---------------------------------------------------------------------------
# ENABLE_DEBUG_TOOLBAR=true
# Set DEBUGPY=1 to have runserver wait for a debugger on DEBUGPY_PORT.
# DEBUGPY=0
# DEBUGPY_PORT=5678
# Container entrypoint behaviour.
# WAIT_FOR_DB=1
# DB_WAIT_ATTEMPTS=30
# RUN_MIGRATIONS=1
# Creates a superuser on container start. A no-op unless all three are set.
# DJANGO_SUPERUSER_USERNAME=
# DJANGO_SUPERUSER_EMAIL=
# DJANGO_SUPERUSER_PASSWORD=
# ---------------------------------------------------------------------------
# Bearer tokens (the mobile app)
# ---------------------------------------------------------------------------
# What the `iss` claim carries. It is also the only thing that tells this
# project's tokens apart from another bearer scheme's on the same header, so
# do not share a value between two deployments that can reach each other.
# Changing it invalidates every token in circulation.
# TOKEN_ISSUER=drf-starter
# An access token cannot be revoked before it expires, so keep this short.
# The refresh token is the one with a revocation story.
# ACCESS_TOKEN_MINUTES=15
# How long someone stays signed in on a phone without retyping a password.
# Rotation plus blacklisting is what makes a value this large safe.
# REFRESH_TOKEN_DAYS=30
# How long the client has to answer a second-factor prompt.
# TOKEN_TWO_FACTOR_CHALLENGE_SECONDS=300
# When the nightly sweep of expired blacklisted refresh tokens runs, in the
# project's TIME_ZONE. Needs a Celery beat process as well as a worker; without
# one the schedule is inert and the table grows forever.
# TOKEN_CLEANUP_HOUR=3
# TOKEN_CLEANUP_MINUTE=30
# ---------------------------------------------------------------------------
# Mobile deep links
#
# Set these and the backend publishes the two association documents that make
# an emailed verification or invitation link open the app instead of the
# browser. Unset, each document 404s -- which is the right answer for a
# deployment with no app. Nothing here is a secret.
# ---------------------------------------------------------------------------
# "<TeamID>.<bundle identifier>", from App Store Connect.
MOBILE_IOS_APP_ID=
# The Android application id.
MOBILE_ANDROID_PACKAGE=
# SHA-256 fingerprints of the signing certificates, comma-separated. More than
# one is normal: with Play App Signing the upload key and the distribution key
# differ, and a debug build differs again. Listing only the release
# fingerprint is why links work in production and open the browser on a
# developer's own handset.
MOBILE_ANDROID_SHA256_FINGERPRINTS=
# The custom scheme the app also answers on, for development where there is no
# verified domain. Must match `scheme` in mobile/app.json.
# MOBILE_APP_SCHEME=drfstarter
# Which client-side paths the app claims. Anything not listed keeps opening in
# the browser, which is what you want for marketing pages and the admin.
# MOBILE_DEEP_LINK_PATHS=/verify-email/*,/confirm-password/*,/invitations/*
# ---------------------------------------------------------------------------
# Push notifications
# ---------------------------------------------------------------------------
# A registry of device tokens, and nothing more -- this project stores them
# and does not send anything. Off by default: an app that never sends a
# notification should not be holding device tokens.
PUSH_ENABLED=false