LumiBaseDocs

Tham chiếu biến môi trường

Dành cho AI agent: Mọi biến bắt buộc phải được đặt trước khi khởi động CMS API. Thiếu biến bắt buộc sẽ khiến quá trình khởi động thất bại kèm thông báo lỗi rõ ràng.

Trang này liệt kê mọi biến môi trường và binding Cloudflare mà LumiBase sử dụng.


Runtime lõi

BiếnBắt buộcMặc địnhMô tả
LUMIBASE_ENV✓—Nhãn môi trường: development, staging, production
LUMIBASE_RUNTIMEChỉ Dockercloudflaredocker cho Node.js/Docker; Cloudflare Workers tự suy ra từ binding
JWT_SECRET✓—Secret để ký/xác thực JWT ứng dụng. Tối thiểu 32 ký tự. Với production Cloudflare, đặt bằng wrangler secret put JWT_SECRET --env production; không bao giờ commit hay đặt trong [env.production.vars].
LUMIBASE_DEV_AUTHChỉ local devfalseĐặt true để bỏ qua auth Logto trong local dev. Không bao giờ bật ở production; pnpm release:check sẽ fail nếu production resolve thành true.
LUMIBASE_REALTIME_ENABLED✗—Chưa implement. Hiện không code nào đọc biến này; đặt nó không có tác dụng gì. Đang được theo dõi như mục tiêu "explicit enablement" trong realtime implementation.
VITE_LUMIBASE_ALLOW_ADMIN_PATH_REDIRECTChỉ setup/debugfalseOpt-in phía client cho phép redirect tiện lợi tới admin path riêng tư. Giữ không đặt ở production, trừ một cửa sổ setup/debug tạm thời có kiểm soát.

Admin path không cấu hình bằng biến môi trường. Nó được chọn trong Setup Wizard và lưu trong database, nên có thể rotate mà không cần redeploy — và không bao giờ nằm trong build artifact.

Đây là trạng thái vận hành riêng tư. Không phơi bày qua biến môi trường VITE_* hay client build metadata, và không tự động redirect các route public/setup tới nó ở production. Xem Admin path riêng tư.


Setup lần đầu

BiếnBắt buộcMặc địnhMô tả
LUMIBASE_REQUIRE_SETUP_TOKEN✗ (chỉ Node/Docker)tắttrue, 1 hoặc yes khiến POST /api/v1/setup/complete đòi một setup token dùng một lần. Hãy bật cho mọi instance mà người khác ngoài bạn có thể truy cập trước khi setup xong — nếu không, ai chạm tới cổng trước sẽ tạo được tài khoản admin.

Khi cờ bật, mọi tiến trình phục vụ HTTP (LUMIBASE_PROCESS_ROLE là web hoặc all) sinh token ngay lúc khởi động, trước khi nhận request, và in ra đúng một lần:

text
[lumibase-cms] SETUP_TOKEN=<token>

Dán nó vào setup wizard, hoặc gửi dưới dạng setupToken tới /setup/complete. Chỉ hash SHA-256 của nó được lưu, và hash bị xoá khi setup hoàn tất.

Khởi động lại không in token mới: hash đã lưu được giữ nguyên để token bạn đang có vẫn dùng được, và log khởi động sẽ báo điều đó thay vì in token. Nếu bạn làm mất dòng đó, hãy xoá hash rồi khởi động lại — lần khởi động tiếp theo sẽ in một token mới:

sql
UPDATE lumibase_system_state SET setup_token_hash = NULL WHERE id = 'singleton';

Nhiều replica khởi động cùng lúc chỉ in đúng một token cho cả nhóm, nên hãy đọc nó từ replica nào đã in ra.

Cloudflare Workers: không hỗ trợ. Worker không có bước khởi động tiến trình để sinh token, nên khi cờ bật, /setup/complete trả 503 SETUP_TOKEN_NOT_ISSUED kèm lời giải thích thay vì nhận token. Ở đó hãy để cờ tắt và hoàn tất setup ngay sau khi deploy.


Encryption

BiếnBắt buộcMặc địnhMô tả
ENCRYPTION_KEYTrước lần dùng đầu tiên—Base64 của 32 byte ngẫu nhiên (openssl rand -base64 32). Bọc các field item được mã hoá và seed 2FA TOTP. Được hiểu là khoá version v0. Đặt như một secret (wrangler secret put ENCRYPTION_KEY --env production); không commit và không đặt trong [env.production.vars]
ENCRYPTION_KEY_<id>✗—Khoá có version, ví dụ ENCRYPTION_KEY_v1, dùng khi rotate
ENCRYPTION_ACTIVE_KEY_ID✗khoá duy nhất đang cấu hình, nếu không thì v0Version nào mã hoá dữ liệu mới
ENCRYPTION_KEY[_<id>]_FILE✗—Đường dẫn file để đọc khoá thay cho biến (Docker secrets). Biến trực tiếp thắng

"Trước lần dùng đầu tiên" nghĩa là trước khi có ai enroll 2FA hoặc ghi một field được mã hoá — không phải trước khi boot. Thiếu khoá thì enroll fail closed với 500 chứ không phải một lỗi có mã.

Khi đã có seed thì không bao giờ được xoá khoá. Seed TOTP ghim version khoá đã bọc chúng và không được migration envelope bọc lại, nên cho một khoá cũ về hưu sẽ khoá những user đó ra khỏi yếu tố thứ hai của họ. Rotate cũng không phải biện pháp khắc phục khi lộ khoá. Xem Vận hành khoá mã hoá.


Xác thực (Logto)

BiếnBắt buộcMô tả
LOGTO_ENDPOINT✓URL instance Logto (vd https://your-tenant.logto.app)
LOGTO_APP_ID✓ID ứng dụng Logto
LOGTO_APP_SECRET✓Secret ứng dụng Logto
LOGTO_JWKS_URI✗Override URL JWKS (tự suy từ LOGTO_ENDPOINT nếu không đặt)
CF_ACCESS_CERTS_URLChỉ CF AccessURL JWKS Cloudflare Access cho auth admin tunnel
CF_ACCESS_AUDIENCEChỉ CF AccessAudience tag của ứng dụng Cloudflare Access

Cơ sở dữ liệu

BiếnBắt buộcMô tả
DATABASE_URLChỉ DockerChuỗi kết nối PostgreSQL (vd postgres://user:pass@host:5432/lumibase)
DATABASE_POOL_MIN✗Số kết nối pool DB tối thiểu (mặc định: 2)
DATABASE_POOL_MAX✗Số kết nối pool DB tối đa (mặc định: 10)
DATABASE_SSL✗true để bắt buộc SSL cho kết nối DB

Với Cloudflare Workers, dùng binding HYPERDRIVE (xem Binding Cloudflare).


Cache

BiếnBắt buộcMô tả
REDIS_URLChỉ DockerChuỗi kết nối Redis (vd redis://localhost:6379)
CACHE_TTL_SCHEMA✗TTL cache schema, đơn vị giây (mặc định: 60)
CACHE_TTL_PERMISSIONS✗TTL cache permission, đơn vị giây (mặc định: 300)
CACHE_TTL_SETTINGS✗TTL cache settings, đơn vị giây (mặc định: 60)

Lưu trữ object

BiếnBắt buộcMô tả
S3_ENDPOINTChỉ Docker/S3URL endpoint tương thích S3 (vd MinIO: http://localhost:9000)
S3_ACCESS_KEY_IDChỉ Docker/S3Access key S3
S3_SECRET_ACCESS_KEYChỉ Docker/S3Secret key S3
S3_BUCKETChỉ Docker/S3Tên bucket lưu trữ (mặc định: lumibase-media)
S3_REGION✗Region S3 (mặc định: us-east-1)
S3_PUBLIC_URL✗Base URL công khai cho asset (vd URL CDN trỏ tới bucket)

Tìm kiếm (MeiliSearch)

BiếnBắt buộcMô tả
MEILISEARCH_HOSTNếu bật searchURL instance MeiliSearch
MEILISEARCH_API_KEYNếu bật searchMaster key hoặc search API key của MeiliSearch

AI Copilot

BiếnBắt buộcMô tả
LLM_PROVIDER✗Provider LLM: openai, anthropic, claude, gemini, nvidia, vertex, workers-ai, echo (mặc định: echo)
OPENAI_API_KEYNếu provider openaiAPI key OpenAI
ANTHROPIC_API_KEYNếu provider anthropic / claudeAPI key Anthropic
GEMINI_API_KEYNếu provider geminiAPI key Google Gemini
NVIDIA_API_KEYNếu provider nvidiaKey hosted-inference NVIDIA (build.nvidia.com / NIM). Tính phí bởi NVIDIA.
NVIDIA_BASE_URL✗Override endpoint NVIDIA — vd một container NIM self-host (http://nim:8000/v1). Mặc định https://integrate.api.nvidia.com/v1.
VERTEX_ACCESS_TOKENNếu provider vertexBearer OAuth 2.0 Google Cloud (gcloud auth print-access-token). Token hết hạn (~1h). Tính phí vào Google Cloud, không phải AWS.
VERTEX_PROJECT_IDNếu provider vertexID project Google Cloud sở hữu các model Vertex AI.
VERTEX_LOCATION✗Region Vertex AI (mặc định: us-central1).
LLM_MODEL✗Override tên model (vd gpt-4.1-nano, claude-3-5-haiku-latest, gemini-3.5-flash, meta/llama-3.1-8b-instruct)
WORKERS_AI_GATEWAYChỉ Workers AIURL gateway CF Workers AI

Provider ↔ billing: nvidia và vertex gọi các cloud bên ngoài — lần lượt là NVIDIA và Google Cloud — nên usage của chúng không được tính vào credit AWS. nvidia (hoặc NIM self-host qua NVIDIA_BASE_URL) và MeiliSearch là các phần ăn khớp tự nhiên với hạ tầng host trên AWS.


Email (Resend)

BiếnBắt buộcMô tả
RESEND_API_KEYNếu bật emailAPI key Resend cho email giao dịch
EMAIL_FROMNếu bật emailĐịa chỉ người gửi (vd [email protected])

SCIM provisioning

BiếnBắt buộcMô tả
SCIM_TOKENNếu bật SCIMBearer token xác thực endpoint /scim/v2/

Pressure limiter (Docker / Node.js)

CMS chạy bằng Docker có cơ chế bảo vệ quá tải cho event loop Node.js. Khi bật và process bị nghẽn, API sẽ trả nhanh HTTP 503 với envelope SERVICE_UNAVAILABLE, header Retry-After và X-Lumi-Overload thay vì để request xếp hàng đến lúc container mất phản hồi. Mặc định /health và /metrics được bỏ qua để vẫn kiểm tra được tình trạng instance.

BiếnBắt buộcMặc địnhMô tả
LUMIBASE_PRESSURE_LIMITER_ENABLEDChỉ DockertrueBật guard quá tải Node.js. Chỉ đặt false tạm thời khi đang scale hoặc tối ưu endpoint gây nghẽn.
LUMIBASE_PRESSURE_LIMITER_SAMPLE_INTERVAL✗250Chu kỳ đo pressure, đơn vị mili giây.
LUMIBASE_PRESSURE_LIMITER_MAX_EVENT_LOOP_DELAY✗1000Độ trễ event loop tối đa, đơn vị mili giây, trước khi API trả 503. Đặt false để tắt ngưỡng này.
LUMIBASE_PRESSURE_LIMITER_MAX_EVENT_LOOP_UTILIZATION✗falseNgưỡng utilization tùy chọn, ví dụ 0.99. Mặc định tắt để tránh reject nhầm khi CPU đang bận nhưng vẫn xử lý hữu ích.
LUMIBASE_PRESSURE_LIMITER_RETRY_AFTER✗5Số giây ghi trong header Retry-After.
LUMIBASE_PRESSURE_LIMITER_EXCLUDED_PATHS✗/health,/metricsDanh sách prefix phân tách bằng dấu phẩy vẫn được phục vụ khi guard phát hiện quá tải.

Rate limiting

Một throttle cửa sổ-cố-định bảo vệ API đã xác thực. Nó key theo principal (user → API key → IP) và scope theo site. Khi vượt ngưỡng, nó trả HTTP 429 với envelope RATE_LIMITED kèm X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, và Retry-After. Nó fail open nếu cache không khả dụng, nên là defence-in-depth chứ không phải quota cứng.

Import lớn có thể chạm ngân sách mặc định. Tăng LUMIBASE_RATE_LIMIT_MAX và ưu tiên endpoint bulk — xem Nhập dữ liệu.

BiếnBắt buộcMặc địnhMô tả
LUMIBASE_RATE_LIMIT_MAX✗300Số request tối đa mỗi cửa sổ, mỗi principal, mỗi site.
LUMIBASE_RATE_LIMIT_WINDOW_S✗60Độ dài cửa sổ, đơn vị giây.
LUMIBASE_RATE_LIMIT_DISABLED✗(không đặt)Đặt true để tắt hẳn throttle.
LUMIBASE_DELIVER_RATE_LIMIT✗1200Số request tối đa mỗi phút, theo IP client, trên Delivery API công khai (/api/v1/deliver/*). 0 là tắt. Xem Caching — penetration.
LUMIBASE_NEGATIVE_CACHE_TTL✗30TTL tombstone (giây) cho các trường hợp xác nhận không tồn tại trên đường đọc công khai, trước khi cộng jitter ±20%. 0 là tắt.

GraphQL

Mọi operation GraphQL đều được validate trước khi chạy, đối chiếu với một giới hạn độ sâu và một giới hạn chi phí tĩnh, từ chối các query sâu hoặc rộng bất thường ngay ở tầng parse (CWE-770). Độ sâu là hằng số compile-time (12); chi phí thì tinh chỉnh được. Tăng LUMIBASE_GQL_MAX_COST nếu một query hợp lệ bị từ chối. Xem graphql-api-spec.md.

BiếnBắt buộcMặc địnhMô tả
LUMIBASE_GQL_MAX_COST✗1000Chi phí tĩnh tối đa chấp nhận cho mỗi operation.
LUMIBASE_GQL_DEFAULT_LIST_SIZE✗20Hệ số nhân chi phí cho một list field không có argument phân trang literal (hoặc là variable).
LUMIBASE_GQL_MAX_LIST_MULTIPLIER✗100Trần clamp cho hệ số nhân chi phí của một list field bất kỳ.

Observability

BiếnBắt buộcMô tả
PROMETHEUS_ENABLEDChỉ Dockertrue để phơi bày endpoint /metrics
LOG_LEVEL✗Mức log: debug, info, warn, error (mặc định: info)
LOG_FORMAT✗json (mặc định) hoặc pretty (local dev)

Binding Cloudflare

Cấu hình các binding này trong apps/cms/wrangler.toml (không phải biến môi trường):

BindingLoạiMục đích
HYPERDRIVEHyperdrivePool kết nối PostgreSQL
CONFIG_CACHEKV NamespaceCache schema, permission và settings
MEDIAR2 BucketLưu trữ object media/file
SITE_ROOMDurable ObjectĐiều phối WebSocket theo từng site (realtime)
AIWorkers AIBinding Workers AI cho provider LLM workers-ai
toml
# trích wrangler.toml
[[hyperdrive]]
binding = "HYPERDRIVE"
id = "<your-hyperdrive-id>"

[[kv_namespaces]]
binding = "CONFIG_CACHE"
id = "<your-kv-namespace-id>"

[[r2_buckets]]
binding = "MEDIA"
bucket_name = "lumibase-media"

[durable_objects]
bindings = [{ name = "SITE_ROOM", class_name = "SiteRoom" }]

Checklist bảo mật

Trước khi deploy lên production, xác minh:

  • JWT_SECRET dài ít nhất 32 ký tự và lưu dưới dạng Wrangler Secret hoặc Docker secret
  • LUMIBASE_DEV_AUTH KHÔNG được đặt true
  • Credential database lưu dưới dạng secret, không nằm trong file .env commit vào git
  • S3_SECRET_ACCESS_KEY lưu dưới dạng secret
  • RESEND_API_KEY lưu dưới dạng secret
  • CORS được cấu hình chỉ cho phép domain Studio và consumer của bạn
Last modified: 26/09/2026