Owly Post
Self-hosted

Configuration

Every environment variable, whether it is required, its default, and what it does

All settings live in .env next to docker-compose.yml; .env.example is the annotated template. Change a value, then docker compose up -d to restart what depends on it.

Database

VariableRequiredDefaultDescription
DATABASE_URLyespostgres://owly:owly@localhost:5432/owlyPostgres connection string. Inside the compose network this is overridden to reach the bundled postgres service; the value in .env is what host-run commands such as pnpm migrate use. Point it at an external Postgres to use that instead; add ?sslmode=require for managed providers.
POSTGRES_USERbundledowlyUser for the bundled Postgres container.
POSTGRES_PASSWORDbundlednonePassword for the bundled container. Must be set: compose refuses to start while it is empty. Generate one with openssl rand -base64 24.
POSTGRES_DBbundledowlyDatabase name for the bundled container.
DATABASE_POOL_MAXno10Maximum connections in the app's pool.
PGSSLMODEnounsetrequire or no-verify turns TLS on for the database connection (certificate not verified); disable forces it off. A sslmode= parameter in DATABASE_URL does the same.

"bundled" means required only when you use the bundled Postgres container.

LLM

VariableRequiredDefaultDescription
LLM_PROVIDERnoanthropicanthropic or openai. The openai provider also talks to OpenAI-compatible servers such as Ollama via OPENAI_BASE_URL.
ANTHROPIC_API_KEYwith anthropicnoneClaude API key. Needs API credits; a Claude subscription does not count.
OPENAI_API_KEYwith openainoneOpenAI API key. Ollama accepts any non-empty value, for example ollama.
OPENAI_BASE_URLnounsetBase URL of an OpenAI-compatible server, for example http://host.docker.internal:11434/v1 for Ollama on the Docker host, or https://openrouter.ai/api/v1. Best effort: servers differ in JSON-mode support.
LLM_MODEL_DIGESTnoclaude-sonnet-4-6 (anthropic) / gpt-5 (openai)Model that writes the digest. Needs to handle structured JSON over up to 300 items.
LLM_MODEL_SUMMARYnoclaude-haiku-4-5 (anthropic) / gpt-5-mini (openai)Model that writes per-item summaries and the reader-profile rewrite.

See LLM providers for a worked example per provider.

Digest

VariableRequiredDefaultDescription
DIGEST_LANGUAGEnoenLanguage of summaries and digests, as a language code such as en, nl or de. The UI stays English.
DIGEST_TIMEZONEnoUTCIANA timezone, for example Europe/Amsterdam. Used for the digest week window and for all schedules.

The digest schedule itself (weekly or daily, day and time) is not an environment variable. Set it in the app under Settings; see Scheduling.

Schedules

VariableRequiredDefaultDescription
INGEST_CRONno0 */6 * * *When sources are fetched, as a cron expression in DIGEST_TIMEZONE. Default: every six hours.
CLEANUP_CRONno15 4 * * *When the retention cleanup runs. Default: daily at 04:15.
ITEM_CONTENT_RETENTION_DAYSno30Days after fetching before an item's full article text is cleared. Titles, links, summaries, digests and feedback are kept forever. 0 disables the cleanup.

Email

Email is optional. It stays disabled until the selected provider is fully configured: for Resend that is RESEND_API_KEY, for SMTP SMTP_HOST, and for both DIGEST_EMAIL_FROM, DIGEST_EMAIL_TO and SITE_URL.

VariableRequiredDefaultDescription
EMAIL_PROVIDERnoresendresend or smtp.
RESEND_API_KEYwith resendnoneResend API key.
SMTP_HOSTwith smtpnoneSMTP server hostname. A relay on the Docker host is reached as host.docker.internal, not localhost.
SMTP_PORTno587SMTP port.
SMTP_USERnononeSMTP username. Leave empty for relays without authentication.
SMTP_PASSnononeSMTP password.
SMTP_SECUREnotrue on port 465, else falsetrue: implicit TLS from the first byte (the port 465 model). false: start plain and upgrade with STARTTLS when the server offers it. Over untrusted networks prefer port 465 with true; STARTTLS can be stripped by an active attacker.
DIGEST_EMAIL_FROMfor emailnoneFrom address. For Resend it must be on a domain verified in Resend.
DIGEST_EMAIL_TOfor emailnoneRecipient of the digest.

Site and security

VariableRequiredDefaultDescription
SITE_URLfor emailnonePublic URL of your deployment, for example https://owly.example.com. Used to build the links back to the app in the digest email. Its hostname is added to the Host allowlist automatically.
ALLOWED_HOSTSnononeComma-separated hostnames the API answers to, for example owly.example.com,owly.internal. Requests with another Host header get 403 Invalid host. (a DNS-rebinding defence). localhost and 127.0.0.1 are always allowed. Needed when you reach the app through a proxy or by LAN name and have not set SITE_URL.

Image

VariableRequiredDefaultDescription
OWLYPOST_TAGnolatestImage tag for ghcr.io/esmeepeters/owlypost. Pin a release with 1.1.0 or 1.1; use dev for a locally built image. See Updating.

Renamed variables

ANTHROPIC_MODEL_DIGEST and ANTHROPIC_MODEL_SUMMARY were renamed to LLM_MODEL_DIGEST and LLM_MODEL_SUMMARY. The old names are no longer read: an install that still sets them silently falls back to the default models until .env is updated.

On this page