Skip to content

Configuration

Weirling reads its settings from environment variables (or .env). ./scripts/init_env.sh writes a .env with fresh secrets; every variable, with a comment, is in .env.example. The tables below cover the ones you are most likely to change.

Settings marked Setup screen can also be changed by the instance owner at /admin/setup. A value set in the environment always wins.

Core

Variable Default What it does
APP_ENV production production or development. Production refuses weak secrets and requires secure cookies.
DEPLOYMENT_MODE selfhost selfhost: one tenant, no quotas, full text in the reader. hosted: plans, quotas, abuse limits.
SECRET_KEY required Signs sessions. Generated by init_env.sh.
REFRESH_SECRET_KEY SECRET_KEY Optional separate secret for refresh tokens.
SECRETS_ENCRYPTION_KEY empty Encrypts secrets saved from the setup screen. Without it, the screen can't store them.
METRICS_TOKEN required Operator token for /metrics and /api/v1/metrics/* (X-Metrics-Token). The instance owner can read the Ingestion page without it.
REGISTRATION_MODE closed (self-host) closed, invite (codes in REGISTRATION_INVITE_CODES) or open. The first account always becomes the owner. Setup screen
EMAIL_VERIFICATION auto auto (required on hosted, off on self-host), required or off.
FRONTEND_URL http://localhost:3001 The web app's address: CORS and links in emails.
CORS_EXTRA_ORIGINS empty More allowed origins, comma-separated (for example the www. host).
PUBLIC_API_URL http://localhost:8000 The API's public address, used in unsubscribe links.
COOKIE_DOMAIN host only Set .example.com when the API and the app are on different subdomains.
COOKIE_SECURE auto HTTPS-only cookies, except on localhost or LAN over HTTP.

Database and Redis

Variable Default What it does
DATABASE_URL postgresql+asyncpg://readprism:readprism@db:5432/readprism Postgres with pgvector. A plain postgres:// URL (Railway, Render, Heroku) is accepted.
DATABASE_SYNC_URL derived from DATABASE_URL Used by migrations.
AUTO_MIGRATE true Run migrations at start-up, under a lock, so several containers migrate once.
DB_POOL / DB_POOL_SIZE / DB_MAX_OVERFLOW auto / 10 / 10 The API pools connections; workers don't (auto). Lower the sizes on small managed databases.
REDIS_URL redis://redis:6379/0 Cache, rate limits, sessions.
CELERY_BROKER_URL redis://redis:6379/1 Job queue.
CELERY_RESULT_BACKEND redis://redis:6379/2 Job results.

The compose Redis keeps an append-only log on the redis_data volume, so a restart keeps sessions and pending sign-in links. make backup snapshots it.

Summaries (LLM)

Variable Default What it does
LLM_API_KEY empty Any OpenAI-compatible key. Without one, summaries are extracts and nothing is sent anywhere. Setup screen
LLM_BASE_URL https://api.groq.com/openai/v1 Groq, OpenAI, OpenRouter, a local Ollama. Setup screen
LLM_MODEL_PRIMARY openai/gpt-oss-120b Story synthesis and interest expansion. Setup screen
LLM_MODEL_FAST openai/gpt-oss-20b Item summaries and topics. Setup screen
LLM_MODEL_SUMMARY, _TOPICS, _SYNTHESIS, _INTERESTS empty Override the model for one task (which model does what).
LLM_SUMMARIZE lazy lazy: only items that reach a digest or the reader. all: every item.
OPENAI_FALLBACK_ENABLED false Fall back to OPENAI_API_KEY / OPENAI_MODEL when the main provider fails.

GROQ_API_KEY is still read in 0.3.x and will be removed; use LLM_API_KEY.

Embeddings and ranking

Variable Default What it does
EMBEDDING_MODEL all-MiniLM-L6-v2 Local sentence-transformers model, or hash (no PyTorch; weaker matching). See switching models.
EMBEDDING_DEVICE cpu cpu or cuda.
OMP_NUM_THREADS / TORCH_NUM_THREADS container CPUs PyTorch threads. By default they follow the container's CPU quota.
SERENDIPITY_DEFAULT_PERCENTAGE 15 Share of each digest kept for discovery.
COLD_START_COLLABORATIVE_ENABLED true "Popular with readers" picks, from 100 active readers and only for items 20 readers finished.
RANKER_VERSION 2 Ranking engine version.

Email

Variable Default What it does
EMAIL_PROVIDER auto auto: Resend when RESEND_API_KEY is set, otherwise SMTP. Or force smtp / resend.
RESEND_API_KEY empty A sending-only Resend key. Use it where outbound SMTP is blocked (Railway Hobby and many clouds).
SMTP_HOST / SMTP_PORT empty / 587 Port 587 uses STARTTLS, 465 uses TLS. Setup screen
SMTP_USER / SMTP_PASSWORD empty The mailbox login. Email is skipped while no provider is configured. Setup screen
FROM_EMAIL / FROM_NAME SMTP_USER / Weirling The sender. With Resend it must be on a verified domain.
REPLY_TO_EMAIL empty Where replies go, for example support@.
SUPPORT_EMAIL grievance contact Help address shown in the app.
GRIEVANCE_CONTACT_EMAIL empty Privacy and takedown contact, shown on /contact.
EMAIL_PHYSICAL_ADDRESS empty Postal address in the email footer. Set it before sending to US readers.

DNS for deliverability (SPF, DKIM, DMARC) is in Install & run.

Hosted service

Variable Default What it does
BILLING_PROVIDER empty lemonsqueezy, paddle or razorpay. While empty, trials never run out: no trial emails, pausing or deletion.
BILLING_WEBHOOK_SECRET / BILLING_API_KEY empty Webhook signature secret and API key for the provider.
BILLING_TRIAL_DAYS 30 Trial length once billing is on.
HOSTED_PAUSED_DELETE_DAYS 30 Days a paused account is kept before deletion (0 never deletes).
READER_FULL_TEXT auto auto: hosted shows only text the publisher put in its feed; self-host shows everything. Or all / feed_only.
HOSTED_FETCH_BUDGET_PER_HOUR 300 Fetches one account may cause per hour.
HOSTED_HOST_POLLS_PER_HOUR 120 Polls of any one website per hour, across all accounts.
HOSTED_MAX_SOURCES_PER_HOST 10 Feeds one account may follow on the same website.
SIGNUP_PER_DOMAIN_PER_HOUR 10 Sign-ups per email domain per hour.
TELEMETRY_RAW_RETENTION_DAYS 90 Raw reading telemetry kept before it is aggregated (0 keeps it).
CONTENT_FULL_TEXT_RETENTION_DAYS 90 Stored article text is cut to an excerpt after this many days.

More on plans, quotas and the account lifecycle: Hosted service.

Fetching

Variable Default What it does
SSRF_PROTECTION_ENABLED true Every fetch resolves the host, refuses private addresses and connects to the checked IP.
BROWSERLESS_URL http://browserless:3000 Headless Chrome for pages that need JavaScript (full profile).
RSSHUB_BASE_URL empty RSSHub bridge for platforms without feeds (bridge profile).